* Re: [RFC][PATCH 0/2] Amlogic T7 (A113D2) Clock Driver
From: Xianwei Zhao @ 2024-04-08 1:39 UTC (permalink / raw)
To: tanure
Cc: Yu Tu, Neil Armstrong, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Stephen Boyd, Michael Turquette, linux-arm-kernel,
linux-amlogic, devicetree, linux-kernel, linux-clk
In-Reply-To: <CAJX_Q+2wA+hNDhYtOsMi-DyuvH0KfkVgbsVFBFDj=Ph4fOEJaw@mail.gmail.com>
Hi Lucas,
Thanks for your reply.
On 2024/4/3 16:12, Lucas Tanure wrote:
> [ EXTERNAL EMAIL ]
>
> On Wed, Apr 3, 2024 at 7:44 AM Xianwei Zhao <xianwei.zhao@amlogic.com> wrote:
>>
>> Hi Lucas,
>> As we are preparing the T7 clock patchset, we would like to your
>> purpose and plan of this RFC patches. Are you going to submit these
>> patches at last?
>
> Hi Xianwei,
>
> I made some progress, and now the SD card controller probes but fails
> to read blocks from the SD card. I do think my port of the clock
> driver is okay, but I will not send my clock driver until the SD card
> fully works, so I am sure the clocking driver is tested.
> But if you have something already done, please send it, and I will
> test and review it from my side.
>
> Any help with the sdcard controller is also much appreciated.
>
The SDCard part works well on our clock patchset. Then we will send the
formal clock submission later. What do you think?
> Thanks
> Lucas
>
>> On 2024/3/18 19:43, Lucas Tanure wrote:
>>> [ EXTERNAL EMAIL ]
>>>
>>> I am trying to port the T7 clock driver from Khadas 5.4 kernel for Vim4
>>> to mainline, but I am encountering some issues in the path.
>>>
>>> The kernel panics at clk_mux_val_to_index, but I believe that all the
>>> needed clocks are registered.
>>>
>>> If anyone from Amlogic or the community could help me understand what
>>> my driver is missing, that would be great.
>>> I will continue to try to figure out, but it has been some weeks
>>> without progress =/.
>>>
>>> Lucas Tanure (2):
>>> clk: meson: T7: add support for Amlogic T7 SoC PLL clock driver
>>> arm64: dts: amlogic: t7: SDCard, Ethernet and Clocking
>>>
>>> .../amlogic/amlogic-t7-a311d2-khadas-vim4.dts | 66 +
>>> arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 189 +
>>> drivers/clk/meson/Kconfig | 25 +
>>> drivers/clk/meson/Makefile | 2 +
>>> drivers/clk/meson/t7-peripherals.c | 6368 +++++++++++++++++
>>> drivers/clk/meson/t7-peripherals.h | 131 +
>>> drivers/clk/meson/t7-pll.c | 1543 ++++
>>> drivers/clk/meson/t7-pll.h | 83 +
>>> .../clock/amlogic,t7-peripherals-clkc.h | 410 ++
>>> .../dt-bindings/clock/amlogic,t7-pll-clkc.h | 69 +
>>> 10 files changed, 8886 insertions(+)
>>> create mode 100644 drivers/clk/meson/t7-peripherals.c
>>> create mode 100644 drivers/clk/meson/t7-peripherals.h
>>> create mode 100644 drivers/clk/meson/t7-pll.c
>>> create mode 100644 drivers/clk/meson/t7-pll.h
>>> create mode 100644 include/dt-bindings/clock/amlogic,t7-peripherals-clkc.h
>>> create mode 100644 include/dt-bindings/clock/amlogic,t7-pll-clkc.h
>>>
>>> Starting kernel ...
>>>
>>> uboot time: 14277917 us
>>> boot 64bit kernel
>>> [ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x410fd092]
>>> [ 0.000000] Linux version 6.8.0-09793-gda876e5b54b3-dirty (tanureal@ryzen) (aarch64-none-linux-gnu-gcc (GNU Toolchain for the A-profile Architecture 10.3-2021.07 (arm-10.29)) 10.3.1 20210621, GNU ld (GNU Toolchain for the A-pr4
>>> [ 0.000000] KASLR disabled due to lack of seed
>>> [ 0.000000] Machine model: Khadas vim4
>>> [ 0.000000] efi: UEFI not found.
>>> [ 0.000000] OF: reserved mem: 0x0000000005000000..0x00000000052fffff (3072 KiB) nomap non-reusable secmon@5000000
>>> [ 0.000000] OF: reserved mem: 0x0000000005300000..0x00000000072fffff (32768 KiB) nomap non-reusable secmon@5300000
>>> [ 0.000000] NUMA: No NUMA configuration found
>>> [ 0.000000] NUMA: Faking a node at [mem 0x0000000000000000-0x00000000df7fffff]
>>> [ 0.000000] NUMA: NODE_DATA [mem 0xdf10c9c0-0xdf10efff]
>>> [ 0.000000] Zone ranges:
>>> [ 0.000000] DMA [mem 0x0000000000000000-0x00000000df7fffff]
>>> [ 0.000000] DMA32 empty
>>> [ 0.000000] Normal empty
>>> [ 0.000000] Movable zone start for each node
>>> [ 0.000000] Early memory node ranges
>>> [ 0.000000] node 0: [mem 0x0000000000000000-0x0000000004ffffff]
>>> [ 0.000000] node 0: [mem 0x0000000005000000-0x00000000072fffff]
>>> [ 0.000000] node 0: [mem 0x0000000007300000-0x00000000df7fffff]
>>> [ 0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x00000000df7fffff]
>>> [ 0.000000] On node 0, zone DMA: 2048 pages in unavailable ranges
>>> [ 0.000000] cma: Reserved 32 MiB at 0x00000000d9800000 on node -1
>>> [ 0.000000] psci: probing for conduit method from DT.
>>> [ 0.000000] psci: PSCIv1.0 detected in firmware.
>>> [ 0.000000] psci: Using standard PSCI v0.2 function IDs
>>> [ 0.000000] psci: Trusted OS migration not required
>>> [ 0.000000] psci: SMC Calling Convention v1.1
>>> [ 0.000000] percpu: Embedded 24 pages/cpu s58152 r8192 d31960 u98304
>>> [ 0.000000] Detected VIPT I-cache on CPU0
>>> [ 0.000000] CPU features: detected: Spectre-v2
>>> [ 0.000000] CPU features: detected: Spectre-v4
>>> [ 0.000000] CPU features: detected: Spectre-BHB
>>> [ 0.000000] CPU features: detected: ARM erratum 858921
>>> [ 0.000000] alternatives: applying boot alternatives
>>> [ 0.000000] Kernel command line: root=UUID=a91e7bfe-4263-4e53-867d-7824e7c6a992 rw rootfstype=ext4 console=ttyS0,921600 no_console_suspend earlycon=ttyS0,0xfe078000 khadas_board=VIM4 androidboot.selinux=permissive androidboot.0
>>> [ 0.000000] Unknown kernel command line parameters "khadas_board=VIM4", will be passed to user space.
>>> [ 0.000000] Dentry cache hash table entries: 524288 (order: 10, 4194304 bytes, linear)
>>> [ 0.000000] Inode-cache hash table entries: 262144 (order: 9, 2097152 bytes, linear)
>>> [ 0.000000] Fallback order for Node 0: 0
>>> [ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 901152
>>> [ 0.000000] Policy zone: DMA
>>> [ 0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
>>> [ 0.000000] software IO TLB: SWIOTLB bounce buffer size adjusted to 3MB
>>> [ 0.000000] software IO TLB: area num 8.
>>> [ 0.000000] software IO TLB: SWIOTLB bounce buffer size roundup to 4MB
>>> [ 0.000000] software IO TLB: mapped [mem 0x00000000d8e00000-0x00000000d9200000] (4MB)
>>> [ 0.000000] Memory: 3445944K/3661824K available (16896K kernel code, 4426K rwdata, 9184K rodata, 9728K init, 611K bss, 183112K reserved, 32768K cma-reserved)
>>> [ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=8, Nodes=1
>>> [ 0.000000] rcu: Preemptible hierarchical RCU implementation.
>>> [ 0.000000] rcu: RCU restricting CPUs from NR_CPUS=256 to nr_cpu_ids=8.
>>> [ 0.000000] Trampoline variant of Tasks RCU enabled.
>>> [ 0.000000] Tracing variant of Tasks RCU enabled.
>>> [ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
>>> [ 0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=8
>>> [ 0.000000] RCU Tasks: Setting shift to 3 and lim to 1 rcu_task_cb_adjust=1.
>>> [ 0.000000] RCU Tasks Trace: Setting shift to 3 and lim to 1 rcu_task_cb_adjust=1.
>>> [ 0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
>>> [ 0.000000] GIC: GICv2 detected, but range too small and irqchip.gicv2_force_probe not set
>>> [ 0.000000] Root IRQ handler: gic_handle_irq
>>> [ 0.000000] rcu: srcu_init: Setting srcu_struct sizes based on contention.
>>> [ 0.000000] arch_timer: Enabling local workaround for ARM erratum 858921
>>> [ 0.000000] arch_timer: CPU0: Trapping CNTVCT access
>>> [ 0.000000] arch_timer: cp15 timer(s) running at 24.00MHz (phys).
>>> [ 0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x588fe9dc0, max_idle_ns: 440795202592 ns
>>> [ 0.000000] sched_clock: 56 bits at 24MHz, resolution 41ns, wraps every 4398046511097ns
>>> [ 0.000210] Console: colour dummy device 80x25
>>> [ 0.000253] Calibrating delay loop (skipped), value calculated using timer frequency.. 48.00 BogoMIPS (lpj=96000)
>>> [ 0.000261] pid_max: default: 32768 minimum: 301
>>> [ 0.000300] LSM: initializing lsm=capability
>>> [ 0.000358] Mount-cache hash table entries: 8192 (order: 4, 65536 bytes, linear)
>>> [ 0.000371] Mountpoint-cache hash table entries: 8192 (order: 4, 65536 bytes, linear)
>>> [ 0.000920] cacheinfo: Unable to detect cache hierarchy for CPU 0
>>> [ 0.001389] rcu: Hierarchical SRCU implementation.
>>> [ 0.001391] rcu: Max phase no-delay instances is 1000.
>>> [ 0.001834] EFI services will not be available.
>>> [ 0.001999] smp: Bringing up secondary CPUs ...
>>> [ 0.002408] CPU features: detected: ARM erratum 845719
>>> [ 0.002426] Detected VIPT I-cache on CPU1
>>> [ 0.002516] CPU1: Booted secondary processor 0x0000000100 [0x410fd034]
>>> [ 0.003007] Detected VIPT I-cache on CPU2
>>> [ 0.003054] CPU2: Booted secondary processor 0x0000000101 [0x410fd034]
>>> [ 0.003497] Detected VIPT I-cache on CPU3
>>> [ 0.003546] CPU3: Booted secondary processor 0x0000000102 [0x410fd034]
>>> [ 0.003988] Detected VIPT I-cache on CPU4
>>> [ 0.004038] CPU4: Booted secondary processor 0x0000000103 [0x410fd034]
>>> [ 0.004472] Detected VIPT I-cache on CPU5
>>> [ 0.004509] arch_timer: Enabling local workaround for ARM erratum 858921
>>> [ 0.004519] arch_timer: CPU5: Trapping CNTVCT access
>>> [ 0.004527] CPU5: Booted secondary processor 0x0000000001 [0x410fd092]
>>> [ 0.004915] Detected VIPT I-cache on CPU6
>>> [ 0.004940] arch_timer: Enabling local workaround for ARM erratum 858921
>>> [ 0.004946] arch_timer: CPU6: Trapping CNTVCT access
>>> [ 0.004951] CPU6: Booted secondary processor 0x0000000002 [0x410fd092]
>>> [ 0.005333] Detected VIPT I-cache on CPU7
>>> [ 0.005358] arch_timer: Enabling local workaround for ARM erratum 858921
>>> [ 0.005364] arch_timer: CPU7: Trapping CNTVCT access
>>> [ 0.005369] CPU7: Booted secondary processor 0x0000000003 [0x410fd092]
>>> [ 0.005414] smp: Brought up 1 node, 8 CPUs
>>> [ 0.005419] SMP: Total of 8 processors activated.
>>> [ 0.005421] CPU: All CPU(s) started at EL2
>>> [ 0.005434] CPU features: detected: 32-bit EL0 Support
>>> [ 0.005437] CPU features: detected: 32-bit EL1 Support
>>> [ 0.005440] CPU features: detected: CRC32 instructions
>>> [ 0.005485] alternatives: applying system-wide alternatives
>>> [ 0.006730] devtmpfs: initialized
>>> [ 0.008534] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
>>> [ 0.008545] futex hash table entries: 2048 (order: 5, 131072 bytes, linear)
>>> [ 0.008989] pinctrl core: initialized pinctrl subsystem
>>> [ 0.009581] DMI not present or invalid.
>>> [ 0.011290] NET: Registered PF_NETLINK/PF_ROUTE protocol family
>>> [ 0.011944] DMA: preallocated 512 KiB GFP_KERNEL pool for atomic allocations
>>> [ 0.012293] DMA: preallocated 512 KiB GFP_KERNEL|GFP_DMA pool for atomic allocations
>>> [ 0.012711] DMA: preallocated 512 KiB GFP_KERNEL|GFP_DMA32 pool for atomic allocations
>>> [ 0.012832] audit: initializing netlink subsys (disabled)
>>> [ 0.013075] audit: type=2000 audit(0.012:1): state=initialized audit_enabled=0 res=1
>>> [ 0.013508] thermal_sys: Registered thermal governor 'step_wise'
>>> [ 0.013512] thermal_sys: Registered thermal governor 'power_allocator'
>>> [ 0.013557] cpuidle: using governor menu
>>> [ 0.013675] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
>>> [ 0.013784] ASID allocator initialised with 65536 entries
>>> [ 0.014630] Serial: AMBA PL011 UART driver
>>> [ 0.017553] Modules: 22496 pages in range for non-PLT usage
>>> [ 0.017556] Modules: 514016 pages in range for PLT usage
>>> [ 0.017980] HugeTLB: registered 1.00 GiB page size, pre-allocated 0 pages
>>> [ 0.017984] HugeTLB: 0 KiB vmemmap can be freed for a 1.00 GiB page
>>> [ 0.017988] HugeTLB: registered 32.0 MiB page size, pre-allocated 0 pages
>>> [ 0.017990] HugeTLB: 0 KiB vmemmap can be freed for a 32.0 MiB page
>>> [ 0.017993] HugeTLB: registered 2.00 MiB page size, pre-allocated 0 pages
>>> [ 0.017995] HugeTLB: 0 KiB vmemmap can be freed for a 2.00 MiB page
>>> [ 0.017997] HugeTLB: registered 64.0 KiB page size, pre-allocated 0 pages
>>> [ 0.018000] HugeTLB: 0 KiB vmemmap can be freed for a 64.0 KiB page
>>> [ 0.018247] Demotion targets for Node 0: null
>>> [ 0.018884] ACPI: Interpreter disabled.
>>> [ 0.019584] iommu: Default domain type: Translated
>>> [ 0.019587] iommu: DMA domain TLB invalidation policy: strict mode
>>> [ 0.019979] SCSI subsystem initialized
>>> [ 0.020174] usbcore: registered new interface driver usbfs
>>> [ 0.020187] usbcore: registered new interface driver hub
>>> [ 0.020200] usbcore: registered new device driver usb
>>> [ 0.020434] pps_core: LinuxPPS API ver. 1 registered
>>> [ 0.020437] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
>>> [ 0.020443] PTP clock support registered
>>> [ 0.020487] EDAC MC: Ver: 3.0.0
>>> [ 0.020717] scmi_core: SCMI protocol bus registered
>>> [ 0.021039] FPGA manager framework
>>> [ 0.021076] Advanced Linux Sound Architecture Driver Initialized.
>>> [ 0.021612] vgaarb: loaded
>>> [ 0.021857] clocksource: Switched to clocksource arch_sys_counter
>>> [ 0.021967] VFS: Disk quotas dquot_6.6.0
>>> [ 0.021984] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
>>> [ 0.022062] pnp: PnP ACPI: disabled
>>> [ 0.026651] NET: Registered PF_INET protocol family
>>> [ 0.026781] IP idents hash table entries: 65536 (order: 7, 524288 bytes, linear)
>>> [ 0.028598] tcp_listen_portaddr_hash hash table entries: 2048 (order: 3, 32768 bytes, linear)
>>> [ 0.028615] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear)
>>> [ 0.028622] TCP established hash table entries: 32768 (order: 6, 262144 bytes, linear)
>>> [ 0.028750] TCP bind hash table entries: 32768 (order: 8, 1048576 bytes, linear)
>>> [ 0.029019] TCP: Hash tables configured (established 32768 bind 32768)
>>> [ 0.029096] UDP hash table entries: 2048 (order: 4, 65536 bytes, linear)
>>> [ 0.029124] UDP-Lite hash table entries: 2048 (order: 4, 65536 bytes, linear)
>>> [ 0.029225] NET: Registered PF_UNIX/PF_LOCAL protocol family
>>> [ 0.029506] RPC: Registered named UNIX socket transport module.
>>> [ 0.029510] RPC: Registered udp transport module.
>>> [ 0.029512] RPC: Registered tcp transport module.
>>> [ 0.029513] RPC: Registered tcp-with-tls transport module.
>>> [ 0.029515] RPC: Registered tcp NFSv4.1 backchannel transport module.
>>> [ 0.029524] PCI: CLS 0 bytes, default 64
>>> [ 0.029649] Unpacking initramfs...
>>> [ 0.033933] kvm [1]: IPA Size Limit: 40 bits
>>> [ 0.034713] kvm [1]: Hyp mode initialized successfully
>>> [ 0.035476] Initialise system trusted keyrings
>>> [ 0.035582] workingset: timestamp_bits=42 max_order=20 bucket_order=0
>>> [ 0.035747] squashfs: version 4.0 (2009/01/31) Phillip Lougher
>>> [ 0.035906] NFS: Registering the id_resolver key type
>>> [ 0.035919] Key type id_resolver registered
>>> [ 0.035922] Key type id_legacy registered
>>> [ 0.035933] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
>>> [ 0.035935] nfs4flexfilelayout_init: NFSv4 Flexfile Layout Driver Registering...
>>> [ 0.036031] 9p: Installing v9fs 9p2000 file system support
>>> [ 0.062587] Key type asymmetric registered
>>> [ 0.062596] Asymmetric key parser 'x509' registered
>>> [ 0.062657] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 245)
>>> [ 0.062661] io scheduler mq-deadline registered
>>> [ 0.062664] io scheduler kyber registered
>>> [ 0.062688] io scheduler bfq registered
>>> [ 0.063318] irq_meson_gpio: 157 to 12 gpio interrupt mux initialized
>>> [ 0.068061] EINJ: ACPI disabled.
>>> [ 0.072570] amlogic_t7_pll_probe
>>> [ 0.072855] amlogic_t7_pll_probe ret 0
>>> [ 0.072943] amlogic_a1_periphs_probe
>>> [ 0.078155] amlogic_a1_periphs_probe ret 0
>>> [ 0.084876] Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled
>>> [ 0.086691] fe078000.serial: ttyS0 at MMIO 0xfe078000 (irq = 14, base_baud = 1500000) is a meson_uart
>>> [ 0.086710] printk: legacy console [ttyS0] enabled
>>> [ 0.229167] sysfs: cannot create duplicate filename '/class/tty/ttyS0'
>>> [ 0.229669] CPU: 3 PID: 1 Comm: swapper/0 Not tainted 6.8.0-09793-gda876e5b54b3-dirty #15
>>> [ 0.230684] Hardware name: Khadas vim4 (DT)
>>> [ 0.231205] Call trace:
>>> [ 0.231509] dump_backtrace+0x94/0xec
>>> [ 0.231963] show_stack+0x18/0x24
>>> [ 0.232374] dump_stack_lvl+0x78/0x90
>>> [ 0.232829] dump_stack+0x18/0x24
>>> [ 0.233241] sysfs_warn_dup+0x64/0x80
>>> [ 0.233696] sysfs_do_create_link_sd+0xf0/0xf8
>>> [ 0.234248] sysfs_create_link+0x20/0x40
>>> [ 0.234736] device_add+0x27c/0x77c
>>> [ 0.235169] device_register+0x20/0x30
>>> [ 0.235635] tty_register_device_attr+0xfc/0x240
>>> [ 0.236209] tty_port_register_device_attr_serdev+0x8c/0xac
>>> [ 0.236902] serial_core_register_port+0x318/0x658
>>> [ 0.237498] serial_ctrl_register_port+0x10/0x1c
>>> [ 0.238072] uart_add_one_port+0x10/0x1c
>>> [ 0.238560] meson_uart_probe+0x2c0/0x3b4
>>> [ 0.239058] platform_probe+0x68/0xd8
>>> [ 0.239513] really_probe+0x148/0x2b4
>>> [ 0.239968] __driver_probe_device+0x78/0x12c
>>> [ 0.240510] driver_probe_device+0xdc/0x160
>>> [ 0.241030] __driver_attach+0x94/0x19c
>>> [ 0.241507] bus_for_each_dev+0x74/0xd4
>>> [ 0.241983] driver_attach+0x24/0x30
>>> [ 0.242428] bus_add_driver+0xe4/0x1e8
>>> [ 0.242893] driver_register+0x60/0x128
>>> [ 0.243370] __platform_driver_register+0x28/0x34
>>> [ 0.243955] meson_uart_platform_driver_init+0x1c/0x28
>>> [ 0.244594] do_one_initcall+0x6c/0x1b0
>>> [ 0.245071] kernel_init_freeable+0x1cc/0x294
>>> [ 0.245613] kernel_init+0x20/0x1dc
>>> [ 0.246046] ret_from_fork+0x10/0x20
>>> [ 0.246555] meson_uart fe078000.serial: Cannot register tty device on line 0
>>> [ 0.247729] msm_serial: driver initialized
>>> [ 0.248150] SuperH (H)SCI(F) driver initialized
>>> [ 0.248544] STM32 USART driver initialized
>>> [ 0.263927] loop: module loaded
>>> [ 0.264952] megasas: 07.727.03.00-rc1
>>> [ 0.271065] tun: Universal TUN/TAP device driver, 1.6
>>> [ 0.271824] thunder_xcv, ver 1.0
>>> [ 0.271878] thunder_bgx, ver 1.0
>>> [ 0.271956] nicpf, ver 1.0
>>> [ 0.273230] hns3: Hisilicon Ethernet Network Driver for Hip08 Family - version
>>> [ 0.273437] hns3: Copyright (c) 2017 Huawei Corporation.
>>> [ 0.274148] hclge is initializing
>>> [ 0.274541] e1000: Intel(R) PRO/1000 Network Driver
>>> [ 0.275116] e1000: Copyright (c) 1999-2006 Intel Corporation.
>>> [ 0.275860] e1000e: Intel(R) PRO/1000 Network Driver
>>> [ 0.276449] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
>>> [ 0.277209] igb: Intel(R) Gigabit Ethernet Network Driver
>>> [ 0.277867] igb: Copyright (c) 2007-2014 Intel Corporation.
>>> [ 0.278576] igbvf: Intel(R) Gigabit Virtual Function Network Driver
>>> [ 0.279330] igbvf: Copyright (c) 2009 - 2012 Intel Corporation.
>>> [ 0.280319] sky2: driver version 1.30
>>> [ 0.281597] VFIO - User Level meta-driver version: 0.3
>>> [ 0.283859] usbcore: registered new interface driver usb-storage
>>> [ 0.286328] i2c_dev: i2c /dev entries driver
>>> [ 0.292404] sdhci: Secure Digital Host Controller Interface driver
>>> [ 0.292481] sdhci: Copyright(c) Pierre Ossman
>>> [ 0.293577] Synopsys Designware Multimedia Card Interface Driver
>>> [ 0.294572] sdhci-pltfm: SDHCI platform and OF driver helper
>>> [ 0.296259] ledtrig-cpu: registered to indicate activity on CPUs
>>> [ 0.298966] meson-sm: secure-monitor enabled
>>> [ 0.299963] usbcore: registered new interface driver usbhid
>>> [ 0.299997] usbhid: USB HID core driver
>>> [ 0.306803] NET: Registered PF_PACKET protocol family
>>> [ 0.306919] 9pnet: Installing 9P2000 support
>>> [ 0.307331] Key type dns_resolver registered
>>> [ 0.318926] Timer migration: 1 hierarchy levels; 8 children per group; 1 crossnode level
>>> [ 0.319462] registered taskstats version 1
>>> [ 0.319968] Loading compiled-in X.509 certificates
>>> [ 0.362771] clk: Disabling unused clocks
>>> [ 0.363100] PM: genpd: Disabling unused power domains
>>> [ 0.363383] ALSA device list:
>>> [ 0.363580] No soundcards found.
>>> [ 0.368194] meson-gx-mmc fe08a000.sd: Got CD GPIO
>>> [ 0.368524] SError Interrupt on CPU6, code 0x00000000bf000002 -- SError
>>> [ 0.368531] CPU: 6 PID: 87 Comm: kworker/u32:3 Not tainted 6.8.0-09793-gda876e5b54b3-dirty #15
>>> [ 0.368537] Hardware name: Khadas vim4 (DT)
>>> [ 0.368540] Workqueue: async async_run_entry_fn
>>> [ 0.368552] pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
>>> [ 0.368556] pc : clk_mux_val_to_index+0x0/0xc0
>>> [ 0.368565] lr : clk_mux_get_parent+0x4c/0x84
>>> [ 0.368571] sp : ffff800082efba10
>>> [ 0.368572] x29: ffff800082efba10 x28: ffff8000823279c0 x27: ffff800082327000
>>> [ 0.368578] x26: ffff000004c361c0 x25: 0000000000000000 x24: 0000000000000002
>>> [ 0.368584] x23: ffff000003f1d300 x22: ffff000003f1d2a0 x21: ffff000004c37280
>>> [ 0.368589] x20: ffff000004c36ec0 x19: ffff000004bba800 x18: 0000000000000020
>>> [ 0.368594] x17: ffff000000022000 x16: 0000000000000003 x15: ffffffffffffffff
>>> [ 0.368599] x14: ffffffffffffffff x13: 0078756d2364732e x12: 3030306138306566
>>> [ 0.368604] x11: 7f7f7f7f7f7f7f7f x10: ffff7fff83438910 x9 : 0000000000000005
>>> [ 0.368609] x8 : 0101010101010101 x7 : 0000000000000000 x6 : 05114367045e5359
>>> [ 0.368613] x5 : 0000000000000006 x4 : 0000000000000000 x3 : 0000000000000000
>>> [ 0.368618] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff000004c36ec0
>>> [ 0.368624] Kernel panic - not syncing: Asynchronous SError Interrupt
>>> [ 0.368626] CPU: 6 PID: 87 Comm: kworker/u32:3 Not tainted 6.8.0-09793-gda876e5b54b3-dirty #15
>>> [ 0.368630] Hardware name: Khadas vim4 (DT)
>>> [ 0.368631] Workqueue: async async_run_entry_fn
>>> [ 0.368635] Call trace:
>>> [ 0.368637] dump_backtrace+0x94/0xec
>>> [ 0.368644] show_stack+0x18/0x24
>>> [ 0.368649] dump_stack_lvl+0x38/0x90
>>> [ 0.368656] dump_stack+0x18/0x24
>>> [ 0.368661] panic+0x388/0x3c8
>>> [ 0.368666] nmi_panic+0x48/0x94
>>> [ 0.368670] arm64_serror_panic+0x6c/0x78
>>> [ 0.368674] do_serror+0x3c/0x78
>>> [ 0.368677] el1h_64_error_handler+0x30/0x48
>>> [ 0.368681] el1h_64_error+0x64/0x68
>>> [ 0.368684] clk_mux_val_to_index+0x0/0xc0
>>> [ 0.368689] __clk_register+0x440/0x82c
>>> [ 0.368693] devm_clk_register+0x5c/0xbc
>>> [ 0.368697] meson_mmc_clk_init+0x11c/0x2a8
>>> [ 0.368702] meson_mmc_probe+0x18c/0x3c0
>>> [ 0.368705] platform_probe+0x68/0xd8
>>> [ 0.368711] really_probe+0x148/0x2b4
>>> [ 0.368714] __driver_probe_device+0x78/0x12c
>>> [ 0.368718] driver_probe_device+0xdc/0x160
>>> [ 0.368721] __device_attach_driver+0xb8/0x134
>>> [ 0.368724] bus_for_each_drv+0x84/0xe0
>>> [ 0.368727] __device_attach_async_helper+0xac/0xd0
>>> [ 0.368730] async_run_entry_fn+0x34/0xe0
>>> [ 0.368734] process_one_work+0x150/0x294
>>> [ 0.368740] worker_thread+0x304/0x408
>>> [ 0.368744] kthread+0x118/0x11c
>>> [ 0.368748] ret_from_fork+0x10/0x20
>>> [ 0.368753] SMP: stopping secondary CPUs
>>> [ 0.368760] Kernel Offset: disabled
>>> [ 0.368761] CPU features: 0x0,00000060,d0080000,0200421b
>>> [ 0.368765] Memory Limit: none
>>> [ 0.400328] ---[ end Kernel panic - not syncing: Asynchronous SError Interrupt ]---
>>>
>>>
>>> --
>>> 2.44.0
>>>
^ permalink raw reply
* Re: (subset) [PATCH v3 1/2] dt-bindings: arm: qcom: Add Motorola Moto G (2013)
From: Bjorn Andersson @ 2024-04-08 1:37 UTC (permalink / raw)
To: Konrad Dybcio, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Stanislav Jakubek
Cc: linux-arm-msm, devicetree, linux-arm-kernel, phone-devel,
linux-kernel
In-Reply-To: <32c507337ab80c550fb1df08f7014d1e31eb4c32.1712480582.git.stano.jakubek@gmail.com>
On Sun, 07 Apr 2024 11:05:10 +0200, Stanislav Jakubek wrote:
> Document the Motorola Moto G (2013), which is a smartphone based
> on the Qualcomm MSM8226 SoC.
>
>
Applied, thanks!
[1/2] dt-bindings: arm: qcom: Add Motorola Moto G (2013)
commit: 4785ec47ec890fe66f31ee886a767dbdf2ea6bae
[2/2] ARM: dts: qcom: Add support for Motorola Moto G (2013)
commit: 49481b6a8f35017af23e9fdfb644095f50a474e3
Best regards,
--
Bjorn Andersson <andersson@kernel.org>
^ permalink raw reply
* Re: [PATCH 0/2] Small fixes for MSM8974 SoC dtsi
From: Bjorn Andersson @ 2024-04-08 1:37 UTC (permalink / raw)
To: ~postmarketos/upstreaming, phone-devel, Konrad Dybcio,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Luca Weiss
Cc: linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20240318-msm8974-misc2-v1-0-f71668a2b8cd@z3ntu.xyz>
On Mon, 18 Mar 2024 10:24:40 +0100, Luca Weiss wrote:
> One fix for dt schema validation, one for the /chosen node.
>
>
Applied, thanks!
[1/2] ARM: dts: qcom: msm8974: Add @0 to memory node name
commit: cad23ffd46e2205582f5a9e9014b3d78ec0256db
[2/2] ARM: dts: qcom: msm8974: Add empty chosen node
commit: 7018981366d496db4b7d5f6a5c2673683d2b1639
Best regards,
--
Bjorn Andersson <andersson@kernel.org>
^ permalink raw reply
* [PATCH v5 6/7] PCI: dwc: rcar-gen4: Add support for r8a779g0
From: Yoshihiro Shimoda @ 2024-04-08 1:24 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda
In-Reply-To: <20240408012458.3717977-1-yoshihiro.shimoda.uh@renesas.com>
This driver previously supported r8a779f0 (R-Car S4-8). Add support
for r8a779g0 (R-Car V4H).
To support r8a779g0, it requires specific firmware.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 201 +++++++++++++++++++-
1 file changed, 200 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 47ec394885f5..a62804674f4e 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -5,8 +5,10 @@
*/
#include <linux/delay.h>
+#include <linux/firmware.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pci.h>
@@ -20,9 +22,10 @@
/* Renesas-specific */
/* PCIe Mode Setting Register 0 */
#define PCIEMSR0 0x0000
-#define BIFUR_MOD_SET_ON BIT(0)
+#define APP_SRIS_MODE BIT(6)
#define DEVICE_TYPE_EP 0
#define DEVICE_TYPE_RC BIT(4)
+#define BIFUR_MOD_SET_ON BIT(0)
/* PCIe Interrupt Status 0 */
#define PCIEINTSTS0 0x0084
@@ -37,19 +40,47 @@
#define PCIEDMAINTSTSEN 0x0314
#define PCIEDMAINTSTSEN_INIT GENMASK(15, 0)
+/* Port Logic Registers 89 */
+#define PRTLGC89 0x0b70
+
+/* Port Logic Registers 90 */
+#define PRTLGC90 0x0b74
+
/* PCIe Reset Control Register 1 */
#define PCIERSTCTRL1 0x0014
#define APP_HOLD_PHY_RST BIT(16)
#define APP_LTSSM_ENABLE BIT(0)
+/* PCIe Power Management Control */
+#define PCIEPWRMNGCTRL 0x0070
+#define APP_CLK_REQ_N BIT(11)
+#define APP_CLK_PM_EN BIT(10)
+
+/*
+ * The R-Car Gen4 documents don't describe the PHY registers' name.
+ * But, the initialization procedure describes these offsets. So,
+ * this driver makes up own #defines for the offsets.
+ */
+#define RCAR_GEN4_PCIE_PHY_0f8 0x0f8
+#define RCAR_GEN4_PCIE_PHY_148 0x148
+#define RCAR_GEN4_PCIE_PHY_1d4 0x1d4
+#define RCAR_GEN4_PCIE_PHY_514 0x514
+#define RCAR_GEN4_PCIE_PHY_700 0x700
+
#define RCAR_NUM_SPEED_CHANGE_RETRIES 10
#define RCAR_MAX_LINK_SPEED 4
#define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET 0x1000
#define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET 0x800
+#define RCAR_GEN4_PCIE_FIRMWARE_NAME "rcar_gen4_pcie.bin"
+#define RCAR_GEN4_PCIE_FIRMWARE_BASE_ADDR 0xc000
+
+MODULE_FIRMWARE(RCAR_GEN4_PCIE_FIRMWARE_NAME);
+
struct rcar_gen4_pcie;
struct rcar_gen4_pcie_platdata {
+ void (*additional_common_init)(struct rcar_gen4_pcie *rcar);
int (*ltssm_enable)(struct rcar_gen4_pcie *rcar);
enum dw_pcie_device_mode mode;
};
@@ -57,12 +88,144 @@ struct rcar_gen4_pcie_platdata {
struct rcar_gen4_pcie {
struct dw_pcie dw;
void __iomem *base;
+ void __iomem *phy_base;
struct platform_device *pdev;
const struct rcar_gen4_pcie_platdata *platdata;
};
#define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
/* Common */
+static void rcar_gen4_pcie_phy_reg_update_bits(struct rcar_gen4_pcie *rcar,
+ u32 offset, u32 mask, u32 val)
+{
+ u32 tmp;
+
+ tmp = readl(rcar->phy_base + offset);
+ tmp &= ~mask;
+ tmp |= val;
+ writel(tmp, rcar->phy_base + offset);
+}
+
+static int rcar_gen4_pcie_reg_check_bit(struct rcar_gen4_pcie *rcar,
+ u32 offset, u32 mask)
+{
+ struct dw_pcie *dw = &rcar->dw;
+
+ if (dw_pcie_readl_dbi(dw, offset) & mask)
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int rcar_gen4_pcie_update_phy_firmware(struct rcar_gen4_pcie *rcar)
+{
+ const u32 check_addr[] = { 0x00101018, 0x00101118, 0x00101021, 0x00101121};
+ struct dw_pcie *dw = &rcar->dw;
+ const struct firmware *fw;
+ unsigned int i, timeout;
+ u32 data;
+ int ret;
+
+ ret = request_firmware(&fw, RCAR_GEN4_PCIE_FIRMWARE_NAME, dw->dev);
+ if (ret) {
+ dev_err(dw->dev, "%s: Requesting firmware failed\n", __func__);
+ return ret;
+ }
+
+ for (i = 0; i < (fw->size / 2); i++) {
+ data = fw->data[i * 2] | fw->data[(i * 2) + 1] << 8;
+ timeout = 100;
+ do {
+ dw_pcie_writel_dbi(dw, PRTLGC89, RCAR_GEN4_PCIE_FIRMWARE_BASE_ADDR + i);
+ dw_pcie_writel_dbi(dw, PRTLGC90, data);
+ if (rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC89, BIT(30)) >= 0)
+ break;
+ if (!(--timeout)) {
+ ret = -ETIMEDOUT;
+ goto exit;
+ }
+ usleep_range(100, 200);
+ } while (1);
+ }
+
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_0f8, BIT(17), BIT(17));
+
+ for (i = 0; i < ARRAY_SIZE(check_addr); i++) {
+ timeout = 100;
+ do {
+ dw_pcie_writel_dbi(dw, PRTLGC89, check_addr[i]);
+ ret = rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC89, BIT(30));
+ ret |= rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC90, BIT(0));
+ if (ret >= 0)
+ break;
+ if (!(--timeout)) {
+ ret = -ETIMEDOUT;
+ goto exit;
+ }
+ usleep_range(100, 200);
+ } while (1);
+ }
+
+ ret = 0;
+exit:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int rcar_gen4_pcie_enable_phy(struct rcar_gen4_pcie *rcar)
+{
+ struct dw_pcie *dw = &rcar->dw;
+ u32 val;
+ int ret;
+
+ val = dw_pcie_readl_dbi(dw, PCIE_PORT_FORCE);
+ val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
+ dw_pcie_writel_dbi(dw, PCIE_PORT_FORCE, val);
+
+ val = readl(rcar->base + PCIEMSR0);
+ val |= APP_SRIS_MODE;
+ writel(val, rcar->base + PCIEMSR0);
+
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_700, BIT(28), 0);
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_700, BIT(20), 0);
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_700, BIT(12), 0);
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_700, BIT(4), 0);
+
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_148,
+ GENMASK(23, 22), BIT(22));
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_148,
+ GENMASK(18, 16), GENMASK(17, 16));
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_148,
+ GENMASK(7, 6), BIT(6));
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_148,
+ GENMASK(2, 0), GENMASK(11, 0));
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_1d4,
+ GENMASK(16, 15), GENMASK(16, 15));
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_514, BIT(26), BIT(26));
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_0f8, BIT(16), 0);
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, RCAR_GEN4_PCIE_PHY_0f8, BIT(19), BIT(19));
+
+ val = readl(rcar->base + PCIERSTCTRL1);
+ val &= ~APP_HOLD_PHY_RST;
+ writel(val, rcar->base + PCIERSTCTRL1);
+
+ ret = readl_poll_timeout(rcar->phy_base + RCAR_GEN4_PCIE_PHY_0f8, val,
+ !(val & BIT(18)), 100, 10000);
+ if (ret < 0)
+ return ret;
+
+ ret = rcar_gen4_pcie_update_phy_firmware(rcar);
+ if (ret)
+ return ret;
+
+ val = readl(rcar->base + PCIERSTCTRL1);
+ val |= APP_LTSSM_ENABLE;
+ writel(val, rcar->base + PCIERSTCTRL1);
+
+ return 0;
+}
+
static void rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar,
bool enable)
{
@@ -200,6 +363,9 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
if (ret)
goto err_unprepare;
+ if (rcar->platdata->additional_common_init)
+ rcar->platdata->additional_common_init(rcar);
+
return 0;
err_unprepare:
@@ -241,6 +407,10 @@ static void rcar_gen4_pcie_unprepare(struct rcar_gen4_pcie *rcar)
static int rcar_gen4_pcie_get_resources(struct rcar_gen4_pcie *rcar)
{
+ rcar->phy_base = devm_platform_ioremap_resource_byname(rcar->pdev, "phy");
+ if (IS_ERR(rcar->phy_base))
+ return PTR_ERR(rcar->base);
+
/* Renesas-specific registers */
rcar->base = devm_platform_ioremap_resource_byname(rcar->pdev, "app");
@@ -517,6 +687,31 @@ static int r8a779f0_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar)
return 0;
}
+static void rcar_gen4_pcie_additional_common_init(struct rcar_gen4_pcie *rcar)
+{
+ struct dw_pcie *dw = &rcar->dw;
+ u32 val;
+
+ /*
+ * The SoC manual said the register setting is required. Otherwise,
+ * linkup failed.
+ */
+ val = dw_pcie_readl_dbi(dw, PCIE_PORT_LANE_SKEW);
+ val &= ~PORT_LANE_SKEW_INSERT_MASK;
+ if (dw->num_lanes < 4)
+ val |= BIT(6);
+ dw_pcie_writel_dbi(dw, PCIE_PORT_LANE_SKEW, val);
+
+ val = readl(rcar->base + PCIEPWRMNGCTRL);
+ val |= APP_CLK_REQ_N | APP_CLK_PM_EN;
+ writel(val, rcar->base + PCIEPWRMNGCTRL);
+}
+
+static int rcar_gen4_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar)
+{
+ return rcar_gen4_pcie_enable_phy(rcar);
+}
+
static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie = {
.ltssm_enable = r8a779f0_pcie_ltssm_enable,
.mode = DW_PCIE_RC_TYPE,
@@ -528,10 +723,14 @@ static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie_ep = {
};
static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie = {
+ .additional_common_init = rcar_gen4_pcie_additional_common_init,
+ .ltssm_enable = rcar_gen4_pcie_ltssm_enable,
.mode = DW_PCIE_RC_TYPE,
};
static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie_ep = {
+ .additional_common_init = rcar_gen4_pcie_additional_common_init,
+ .ltssm_enable = rcar_gen4_pcie_ltssm_enable,
.mode = DW_PCIE_EP_TYPE,
};
--
2.25.1
^ permalink raw reply related
* [PATCH v5 4/7] PCI: dwc: rcar-gen4: Add rcar_gen4_pcie_platdata
From: Yoshihiro Shimoda @ 2024-04-08 1:24 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda
In-Reply-To: <20240408012458.3717977-1-yoshihiro.shimoda.uh@renesas.com>
This driver supports r8a779f0 now. In the future, add support for
r8a779g0 and r8a779h0. To support these new SoCs, need other
initializing settings. So, at first, add rcar_gen4_pcie_platdata
and have a member with mode. No behavior changes.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 30 ++++++++++++++-------
1 file changed, 21 insertions(+), 9 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 0be760ed420b..da2821d6efce 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -48,11 +48,15 @@
#define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET 0x1000
#define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET 0x800
+struct rcar_gen4_pcie_platdata {
+ enum dw_pcie_device_mode mode;
+};
+
struct rcar_gen4_pcie {
struct dw_pcie dw;
void __iomem *base;
struct platform_device *pdev;
- enum dw_pcie_device_mode mode;
+ const struct rcar_gen4_pcie_platdata *platdata;
};
#define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
@@ -137,7 +141,7 @@ static int rcar_gen4_pcie_start_link(struct dw_pcie *dw)
* Since dw_pcie_setup_rc() sets it once, PCIe Gen2 will be trained.
* So, this needs remaining times for up to PCIe Gen4 if RC mode.
*/
- if (changes && rcar->mode == DW_PCIE_RC_TYPE)
+ if (changes && rcar->platdata->mode == DW_PCIE_RC_TYPE)
changes--;
for (i = 0; i < changes; i++) {
@@ -172,9 +176,9 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
reset_control_assert(dw->core_rsts[DW_PCIE_PWR_RST].rstc);
val = readl(rcar->base + PCIEMSR0);
- if (rcar->mode == DW_PCIE_RC_TYPE) {
+ if (rcar->platdata->mode == DW_PCIE_RC_TYPE) {
val |= DEVICE_TYPE_RC;
- } else if (rcar->mode == DW_PCIE_EP_TYPE) {
+ } else if (rcar->platdata->mode == DW_PCIE_EP_TYPE) {
val |= DEVICE_TYPE_EP;
} else {
ret = -EINVAL;
@@ -437,9 +441,9 @@ static void rcar_gen4_remove_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
/* Common */
static int rcar_gen4_add_dw_pcie(struct rcar_gen4_pcie *rcar)
{
- rcar->mode = (uintptr_t)of_device_get_match_data(&rcar->pdev->dev);
+ rcar->platdata = of_device_get_match_data(&rcar->pdev->dev);
- switch (rcar->mode) {
+ switch (rcar->platdata->mode) {
case DW_PCIE_RC_TYPE:
return rcar_gen4_add_dw_pcie_rp(rcar);
case DW_PCIE_EP_TYPE:
@@ -480,7 +484,7 @@ static int rcar_gen4_pcie_probe(struct platform_device *pdev)
static void rcar_gen4_remove_dw_pcie(struct rcar_gen4_pcie *rcar)
{
- switch (rcar->mode) {
+ switch (rcar->platdata->mode) {
case DW_PCIE_RC_TYPE:
rcar_gen4_remove_dw_pcie_rp(rcar);
break;
@@ -500,14 +504,22 @@ static void rcar_gen4_pcie_remove(struct platform_device *pdev)
rcar_gen4_pcie_unprepare(rcar);
}
+static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie = {
+ .mode = DW_PCIE_RC_TYPE,
+};
+
+static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie_ep = {
+ .mode = DW_PCIE_EP_TYPE,
+};
+
static const struct of_device_id rcar_gen4_pcie_of_match[] = {
{
.compatible = "renesas,rcar-gen4-pcie",
- .data = (void *)DW_PCIE_RC_TYPE,
+ .data = &platdata_rcar_gen4_pcie,
},
{
.compatible = "renesas,rcar-gen4-pcie-ep",
- .data = (void *)DW_PCIE_EP_TYPE,
+ .data = &platdata_rcar_gen4_pcie_ep,
},
{},
};
--
2.25.1
^ permalink raw reply related
* [PATCH v5 7/7] misc: pci_endpoint_test: Document a policy about adding pci_device_id
From: Yoshihiro Shimoda @ 2024-04-08 1:24 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda, Frank Li
In-Reply-To: <20240408012458.3717977-1-yoshihiro.shimoda.uh@renesas.com>
To avoid becoming struct pci_device_id pci_endpoint_test_tbl longer
and longer, document a policy. For example, if PCIe endpoint controller
can configure vendor id and/or product id, you can reuse one of
existing entries to test.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
Cc: Frank Li <Frank.li@nxp.com>
---
drivers/misc/pci_endpoint_test.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index c38a6083f0a7..3c8a0afad91d 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -980,6 +980,7 @@ static const struct pci_endpoint_test_data j721e_data = {
.irq_type = IRQ_TYPE_MSI,
};
+/* Don't need to add a new entry if you can use existing entry to test */
static const struct pci_device_id pci_endpoint_test_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),
.driver_data = (kernel_ulong_t)&default_data,
--
2.25.1
^ permalink raw reply related
* [PATCH v5 2/7] dt-bindings: PCI: rcar-gen4-pci-ep: Add R-Car V4H compatible
From: Yoshihiro Shimoda @ 2024-04-08 1:24 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda, Conor Dooley, Geert Uytterhoeven
In-Reply-To: <20240408012458.3717977-1-yoshihiro.shimoda.uh@renesas.com>
Document bindings for R-Car V4H (R8A779G0) PCIe endpoint module.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
index fe38f62da066..91b81ac75592 100644
--- a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
+++ b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
@@ -16,7 +16,9 @@ allOf:
properties:
compatible:
items:
- - const: renesas,r8a779f0-pcie-ep # R-Car S4-8
+ - enum:
+ - renesas,r8a779f0-pcie-ep # R-Car S4-8
+ - renesas,r8a779g0-pcie-ep # R-Car V4H
- const: renesas,rcar-gen4-pcie-ep # R-Car Gen4
reg:
--
2.25.1
^ permalink raw reply related
* [PATCH v5 5/7] PCI: dwc: rcar-gen4: Add .ltssm_enable() for other SoC support
From: Yoshihiro Shimoda @ 2024-04-08 1:24 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda
In-Reply-To: <20240408012458.3717977-1-yoshihiro.shimoda.uh@renesas.com>
This driver can reuse other R-Car Gen4 SoCs support like r8a779g0 and
r8a779h0. However, r8a779g0 and r8a779h0 require other initializing
settings that differ than r8a779f0. So, add a new function pointer
.ltssm_enable() for it. No behavior changes.
After applied this patch, probing SoCs by rcar_gen4_pcie_of_match[]
will be changed like below:
- r8a779f0 as "renesas,r8a779f0-pcie" and "renesas,r8a779f0-pcie-ep"
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 41 ++++++++++++++++++---
1 file changed, 36 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index da2821d6efce..47ec394885f5 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -48,7 +48,9 @@
#define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET 0x1000
#define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET 0x800
+struct rcar_gen4_pcie;
struct rcar_gen4_pcie_platdata {
+ int (*ltssm_enable)(struct rcar_gen4_pcie *rcar);
enum dw_pcie_device_mode mode;
};
@@ -61,8 +63,8 @@ struct rcar_gen4_pcie {
#define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
/* Common */
-static void rcar_gen4_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar,
- bool enable)
+static void rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar,
+ bool enable)
{
u32 val;
@@ -127,9 +129,13 @@ static int rcar_gen4_pcie_speed_change(struct dw_pcie *dw)
static int rcar_gen4_pcie_start_link(struct dw_pcie *dw)
{
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
- int i, changes;
+ int i, changes, ret;
- rcar_gen4_pcie_ltssm_enable(rcar, true);
+ if (rcar->platdata->ltssm_enable) {
+ ret = rcar->platdata->ltssm_enable(rcar);
+ if (ret)
+ return ret;
+ }
/*
* Require direct speed change with retrying here if the link_gen is
@@ -157,7 +163,7 @@ static void rcar_gen4_pcie_stop_link(struct dw_pcie *dw)
{
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
- rcar_gen4_pcie_ltssm_enable(rcar, false);
+ rcar_gen4_pcie_ltssm_control(rcar, false);
}
static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
@@ -504,6 +510,23 @@ static void rcar_gen4_pcie_remove(struct platform_device *pdev)
rcar_gen4_pcie_unprepare(rcar);
}
+static int r8a779f0_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar)
+{
+ rcar_gen4_pcie_ltssm_control(rcar, true);
+
+ return 0;
+}
+
+static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie = {
+ .ltssm_enable = r8a779f0_pcie_ltssm_enable,
+ .mode = DW_PCIE_RC_TYPE,
+};
+
+static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie_ep = {
+ .ltssm_enable = r8a779f0_pcie_ltssm_enable,
+ .mode = DW_PCIE_EP_TYPE,
+};
+
static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie = {
.mode = DW_PCIE_RC_TYPE,
};
@@ -513,6 +536,14 @@ static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie_ep = {
};
static const struct of_device_id rcar_gen4_pcie_of_match[] = {
+ {
+ .compatible = "renesas,r8a779f0-pcie",
+ .data = &platdata_r8a779f0_pcie,
+ },
+ {
+ .compatible = "renesas,r8a779f0-pcie-ep",
+ .data = &platdata_r8a779f0_pcie_ep,
+ },
{
.compatible = "renesas,rcar-gen4-pcie",
.data = &platdata_rcar_gen4_pcie,
--
2.25.1
^ permalink raw reply related
* [PATCH v5 1/7] dt-bindings: PCI: rcar-gen4-pci-host: Add R-Car V4H compatible
From: Yoshihiro Shimoda @ 2024-04-08 1:24 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda, Conor Dooley, Geert Uytterhoeven
In-Reply-To: <20240408012458.3717977-1-yoshihiro.shimoda.uh@renesas.com>
Document bindings for R-Car V4H (R8A779G0) PCIe host module.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
index ffb34339b637..955c664f1fbb 100644
--- a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
+++ b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
@@ -16,7 +16,9 @@ allOf:
properties:
compatible:
items:
- - const: renesas,r8a779f0-pcie # R-Car S4-8
+ - enum:
+ - renesas,r8a779f0-pcie # R-Car S4-8
+ - renesas,r8a779g0-pcie # R-Car V4H
- const: renesas,rcar-gen4-pcie # R-Car Gen4
reg:
--
2.25.1
^ permalink raw reply related
* [PATCH v5 3/7] PCI: dwc: Add PCIE_PORT_{FORCE,LANE_SKEW} macros
From: Yoshihiro Shimoda @ 2024-04-08 1:24 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda
In-Reply-To: <20240408012458.3717977-1-yoshihiro.shimoda.uh@renesas.com>
R-Car Gen4 PCIe controller needs to use the Synopsys-specific PCIe
configuration registers. So, add the macros.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
drivers/pci/controller/dwc/pcie-designware.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 26dae4837462..aa4db6eaf02a 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -71,6 +71,9 @@
#define LINK_WAIT_IATU 9
/* Synopsys-specific PCIe configuration registers */
+#define PCIE_PORT_FORCE 0x708
+#define PORT_FORCE_DO_DESKEW_FOR_SRIS BIT(23)
+
#define PCIE_PORT_AFR 0x70C
#define PORT_AFR_N_FTS_MASK GENMASK(15, 8)
#define PORT_AFR_N_FTS(n) FIELD_PREP(PORT_AFR_N_FTS_MASK, n)
@@ -92,6 +95,9 @@
#define PORT_LINK_MODE_4_LANES PORT_LINK_MODE(0x7)
#define PORT_LINK_MODE_8_LANES PORT_LINK_MODE(0xf)
+#define PCIE_PORT_LANE_SKEW 0x714
+#define PORT_LANE_SKEW_INSERT_MASK GENMASK(23, 0)
+
#define PCIE_PORT_DEBUG0 0x728
#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f
#define PORT_LOGIC_LTSSM_STATE_L0 0x11
--
2.25.1
^ permalink raw reply related
* [PATCH v5 0/7] PCI: dwc: rcar-gen4: Add R-Car V4H support
From: Yoshihiro Shimoda @ 2024-04-08 1:24 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda
The pcie-rcar-gen4 driver can reuse other R-Car Gen4 support like
r8a779g0 (R-Car V4H) and r8a779h0 (R-Car V4M). However, some
initializing settings differ between R-Car S4-8 (r8a779f0) and
others. The R-Car S4-8 will be minority about the setting way. So,
R-Car V4H will be majority and this is generic initialization way
as "renesas,rcar-gen4-pcie{-ep}" compatible. For now, I tested
both R-Car S4-8 and R-Car V4H on this driver. I'll support one more
other SoC (R-Car V4M) in the future.
Changes from v4:
https://lore.kernel.org/linux-pci/20240403053304.3695096-1-yoshihiro.shimoda.uh@renesas.com/
- Fix compatible string for renesas,r8a779f0-pcie-ep which was described
accidentally from v3...
Changes from v3:
https://lore.kernel.org/linux-pci/20240401023942.134704-1-yoshihiro.shimoda.uh@renesas.com/
- Modify the code to use "do .. while" instead of goto in patch 6/7.
Changes from v2:
https://lore.kernel.org/linux-pci/20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com/
- Add a new patch which just add a platdata in patch 4/7.
- Modify the subjects in patch [56]/7.
- Modify the description and code about Bjorn's comment in patch [56]/7.
- Add missing MODULE_FIRMWARE(9 in patch 6/7.
- Document a policy aboud adding pci_device_id instead of adding r8a779g0's id
in patch 7/7.
Changes from v1:
https://lore.kernel.org/linux-pci/20240229120719.2553638-1-yoshihiro.shimoda.uh@renesas.com/
- Based on v6.9-rc1.
- Add Acked-by and/or Reviewed-by in patch [126/6].
Yoshihiro Shimoda (7):
dt-bindings: PCI: rcar-gen4-pci-host: Add R-Car V4H compatible
dt-bindings: PCI: rcar-gen4-pci-ep: Add R-Car V4H compatible
PCI: dwc: Add PCIE_PORT_{FORCE,LANE_SKEW} macros
PCI: dwc: rcar-gen4: Add rcar_gen4_pcie_platdata
PCI: dwc: rcar-gen4: Add .ltssm_enable() for other SoC support
PCI: dwc: rcar-gen4: Add support for r8a779g0
misc: pci_endpoint_test: Document a policy about adding pci_device_id
.../bindings/pci/rcar-gen4-pci-ep.yaml | 4 +-
.../bindings/pci/rcar-gen4-pci-host.yaml | 4 +-
drivers/misc/pci_endpoint_test.c | 1 +
drivers/pci/controller/dwc/pcie-designware.h | 6 +
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 272 +++++++++++++++++-
5 files changed, 270 insertions(+), 17 deletions(-)
--
2.25.1
^ permalink raw reply
* Re: [PATCH v3 2/2] mailbox: arm_mhuv3: Add driver
From: Jassi Brar @ 2024-04-08 1:14 UTC (permalink / raw)
To: Cristian Marussi
Cc: linux-kernel, linux-arm-kernel, devicetree, sudeep.holla, robh+dt,
krzysztof.kozlowski+dt, conor+dt
In-Reply-To: <20240404062347.3219795-3-cristian.marussi@arm.com>
On Thu, Apr 4, 2024 at 1:25 AM Cristian Marussi
<cristian.marussi@arm.com> wrote:
>
> Add support for ARM MHUv3 mailbox controller.
>
> Support is limited to the MHUv3 Doorbell extension using only the PBX/MBX
> combined interrupts.
>
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> v1 -> v2
> - fixed checkpatch warnings about side-effects
> - fixed sparse errors as reported
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202403290015.tCLXudqC-lkp@intel.com/
> ---
> MAINTAINERS | 9 +
> drivers/mailbox/Kconfig | 11 +
> drivers/mailbox/Makefile | 2 +
> drivers/mailbox/arm_mhuv3.c | 1063 +++++++++++++++++++++++++++++++++++
> 4 files changed, 1085 insertions(+)
> create mode 100644 drivers/mailbox/arm_mhuv3.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index aa3b947fb080..e957b9d9e32a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -12998,6 +12998,15 @@ F: Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml
> F: drivers/mailbox/arm_mhuv2.c
> F: include/linux/mailbox/arm_mhuv2_message.h
>
> +MAILBOX ARM MHUv3
> +M: Sudeep Holla <sudeep.holla@arm.com>
> +M: Cristian Marussi <cristian.marussi@arm.com>
> +L: linux-kernel@vger.kernel.org
> +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
> +S: Maintained
> +F: Documentation/devicetree/bindings/mailbox/arm,mhuv3.yaml
> +F: drivers/mailbox/arm_mhuv3.c
> +
> MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
> M: Alejandro Colomar <alx@kernel.org>
> L: linux-man@vger.kernel.org
> diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
> index 42940108a187..d20cdae65cfe 100644
> --- a/drivers/mailbox/Kconfig
> +++ b/drivers/mailbox/Kconfig
> @@ -23,6 +23,17 @@ config ARM_MHU_V2
> Say Y here if you want to build the ARM MHUv2 controller driver,
> which provides unidirectional mailboxes between processing elements.
>
> +config ARM_MHU_V3
> + tristate "ARM MHUv3 Mailbox"
> + depends on ARM64 || COMPILE_TEST
> + help
> + Say Y here if you want to build the ARM MHUv3 controller driver,
> + which provides unidirectional mailboxes between processing elements.
> +
> + ARM MHUv3 controllers can implement a varying number of extensions
> + that provides different means of transports: supported extensions
> + will be discovered and possibly managed at probe-time.
> +
> config IMX_MBOX
> tristate "i.MX Mailbox"
> depends on ARCH_MXC || COMPILE_TEST
> diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
> index 18793e6caa2f..5cf2f54debaf 100644
> --- a/drivers/mailbox/Makefile
> +++ b/drivers/mailbox/Makefile
> @@ -9,6 +9,8 @@ obj-$(CONFIG_ARM_MHU) += arm_mhu.o arm_mhu_db.o
>
> obj-$(CONFIG_ARM_MHU_V2) += arm_mhuv2.o
>
> +obj-$(CONFIG_ARM_MHU_V3) += arm_mhuv3.o
> +
> obj-$(CONFIG_IMX_MBOX) += imx-mailbox.o
>
> obj-$(CONFIG_ARMADA_37XX_RWTM_MBOX) += armada-37xx-rwtm-mailbox.o
> diff --git a/drivers/mailbox/arm_mhuv3.c b/drivers/mailbox/arm_mhuv3.c
> new file mode 100644
> index 000000000000..e4125568bec0
> --- /dev/null
> +++ b/drivers/mailbox/arm_mhuv3.c
> @@ -0,0 +1,1063 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * ARM Message Handling Unit Version 3 (MHUv3) driver.
> + *
> + * Copyright (C) 2024 ARM Ltd.
> + *
> + * Based on ARM MHUv2 driver.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/interrupt.h>
> +#include <linux/mailbox_controller.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +
> +/* ====== MHUv3 Registers ====== */
> +
> +/* Maximum number of Doorbell channel windows */
> +#define MHUV3_DBCW_MAX 128
> +/* Number of DBCH combined interrupt status registers */
> +#define MHUV3_DBCH_CMB_INT_ST_REG_CNT 4
> +#define MHUV3_INVALID_DOORBELL 0xFFFFFFFFUL
> +
> +/* Number of FFCH combined interrupt status registers */
> +#define MHUV3_FFCH_CMB_INT_ST_REG_CNT 2
> +
> +#define MHUV3_STAT_BYTES (sizeof(u32))
>
Simply 4 please.
> +#define MHUV3_STAT_BITS (MHUV3_STAT_BYTES * __CHAR_BIT__)
>
just 32.
> +
> +/* Not a typo ... */
> +#define MHUV3_MAJOR_VERSION 2
> +
> +enum {
> + MHUV3_MBOX_CELL_TYPE,
> + MHUV3_MBOX_CELL_CHWN,
> + MHUV3_MBOX_CELL_PARAM,
> + MHUV3_MBOX_CELLS
> +};
> +
> +/* CTRL_Page */
> +
> +struct blk_id {
> + u32 blk_id : 4;
Please avoid name clashes.
> + u32 pad : 28;
> +} __packed;
> +
> +struct feat_spt0 {
> + u32 dbe_spt : 4;
> + u32 fe_spt : 4;
> + u32 fce_spt : 4;
> + u32 tze_spt : 4;
> + u32 rme_spt : 4;
> + u32 rase_spt : 4;
> + u32 pad: 8;
> +} __packed;
> +
> +struct feat_spt1 {
> + u32 auto_op_spt : 4;
> + u32 pad: 28;
> +} __packed;
> +
> +struct dbch_cfg0 {
> + u32 num_dbch : 8;
> + u32 pad: 24;
> +} __packed;
> +
> +struct ffch_cfg0 {
> + u32 num_ffch : 8;
> + u32 x8ba_spt : 1;
> + u32 x16ba_spt : 1;
> + u32 x32ba_spt : 1;
> + u32 x64ba_spt : 1;
> + u32 pad : 4;
> + u32 ffch_depth : 10;
> + u32 pad2 : 6;
> +} __packed;
> +
> +struct fch_cfg0 {
> + u32 num_fch : 10;
> + /* MBX only registers */
> + u32 fcgi_spt : 1;
> + /* ------------------ */
> + u32 num_fcg : 5;
> + u32 num_fch_per_grp : 5;
> + u32 fch_ws : 8;
> + u32 pad : 3;
> +} __packed;
> +
> +struct ctrl {
> + u32 op_req : 1;
> + u32 ch_op_mask : 1;
> + u32 pad : 30;
> +} __packed;
> +
> +struct fch_ctrl {
> + u32 pad : 2;
> + u32 int_en : 1;
> + u32 pad2 : 29;
> +} __packed;
> +
> +struct iidr {
> + u32 implementer : 12;
> + u32 revision : 4;
> + u32 variant : 4;
> + u32 product_id : 12;
> +} __packed;
> +
> +struct aidr {
> + u32 arch_minor_rev : 4;
> + u32 arch_major_rev : 4;
> + u32 pad : 24;
> +} __packed;
> +
I am not sure about using bitfields on register values. I know v2
driver also uses bitfields but this still is not very portable and is
dependent on compiler behaviour. We may actually save some loc by not
having unused fields if we use shifts and masks. Though I don't
strongly feel either way.
> +struct ctrl_page {
> + struct blk_id blk_id;
> + u8 pad[0x10 - 0x4];
> + struct feat_spt0 feat_spt0;
> + struct feat_spt1 feat_spt1;
> + u8 pad1[0x20 - 0x18];
> + struct dbch_cfg0 dbch_cfg0;
> + u8 pad2[0x30 - 0x24];
> + struct ffch_cfg0 ffch_cfg0;
> + u8 pad3[0x40 - 0x34];
> + struct fch_cfg0 fch_cfg0;
> + u8 pad4[0x100 - 0x44];
> + struct ctrl ctrl;
> + /* MBX only registers */
> + u8 pad5[0x140 - 0x104];
> + struct fch_ctrl fch_ctrl;
> + u32 fcg_int_en;
> + u8 pad6[0x400 - 0x148];
> + /* ------------------ */
Why the decoration ? Maybe comment on what different starts from here.
> + u32 dbch_int_st[MHUV3_DBCH_CMB_INT_ST_REG_CNT];
> + u32 ffch_int_st[MHUV3_FFCH_CMB_INT_ST_REG_CNT];
> + /* MBX only registers */
> + u8 pad7[0x470 - 0x418];
> + u32 fcg_int_st;
> + u8 pad8[0x480 - 0x474];
> + u32 fcg_grp_int_st[32];
> + u8 pad9[0xFC8 - 0x500];
> + /* ------------------ */
> + struct iidr iidr;
> + struct aidr aidr;
> + u32 imp_def_id[12];
> +} __packed;
> +
> +/* DBCW_Page */
> +
> +struct xbcw_ctrl {
> + u32 comb_en : 1;
> + u32 pad : 31;
> +} __packed;
> +
> +struct pdbcw_int {
> + u32 tfr_ack : 1;
> + u32 pad : 31;
> +} __packed;
> +
> +struct pdbcw_page {
> + u32 st;
> + u8 pad[0xC - 0x4];
> + u32 set;
> + struct pdbcw_int int_st;
> + struct pdbcw_int int_clr;
> + struct pdbcw_int int_en;
> + struct xbcw_ctrl ctrl;
> +} __packed;
> +
> +struct mdbcw_page {
> + u32 st;
> + u32 st_msk;
> + u32 clr;
> + u8 pad[0x10 - 0xC];
> + u32 msk_st;
> + u32 msk_set;
> + u32 msk_clr;
> + struct xbcw_ctrl ctrl;
> +} __packed;
> +
> +struct dummy_page {
> + u8 pad[0x1000];
> +} __packed;
> +
> +struct mhu3_pbx_frame_reg {
> + struct ctrl_page ctrl;
> + struct pdbcw_page dbcw[MHUV3_DBCW_MAX];
> + struct dummy_page ffcw;
> + struct dummy_page fcw;
> + u8 pad[0xF000 - 0x4000];
> + struct dummy_page impdef;
> +} __packed;
> +
> +struct mhu3_mbx_frame_reg {
> + struct ctrl_page ctrl;
> + struct mdbcw_page dbcw[MHUV3_DBCW_MAX];
> + struct dummy_page ffcw;
> + struct dummy_page fcw;
> + u8 pad[0xF000 - 0x4000];
> + struct dummy_page impdef;
> +} __packed;
> +
> +/* Macro for reading a bitfield within a physically mapped packed struct */
> +#define readl_relaxed_bitfield(_regptr, _field) \
> + ({ \
> + u32 _rval; \
> + typeof(_regptr) _rptr = _regptr; \
> + _rval = readl_relaxed(_rptr); \
> + ((typeof(*_rptr) __force *)(&_rval))->_field; \
> + })
> +
> +/* Macro for writing a bitfield within a physically mapped packed struct */
> +#define writel_relaxed_bitfield(_value, _regptr, _field) \
> + ({ \
> + u32 _rval; \
> + typeof(_regptr) _rptr = _regptr; \
> + _rval = readl_relaxed(_rptr); \
> + ((typeof(*_rptr) __force *)(&_rval))->_field = _value; \
> + writel_relaxed(_rval, _rptr); \
> + })
> +
> +/* ====== MHUv3 data structures ====== */
> +
> +enum mhuv3_frame {
> + PBX_FRAME,
> + MBX_FRAME
> +};
> +
> +static char *mhuv3_str[] = {
> + "PBX",
> + "MBX"
> +};
> +
> +enum mhuv3_extension_type {
> + FIRST_EXT = 0,
> + DBE_EXT = FIRST_EXT,
> + FCE_EXT,
> + FE_EXT,
> + MAX_EXT
> +};
> +
> +struct mhuv3;
> +
> +/**
> + * struct mhuv3_protocol_ops - MHUv3 operations
> + *
> + * @rx_startup: Receiver startup callback.
> + * @rx_shutdown: Receiver shutdown callback.
> + * @read_data: Read available Sender in-band LE data (if any).
> + * @rx_complete: Acknowledge data reception to the Sender. Any out-of-band data
> + * has to have been already retrieved before calling this.
> + * @tx_startup: Sender startup callback.
> + * @tx_shutdown: Sender shutdown callback.
> + * @last_tx_done: Report back to the Sender if the last transfer has completed.
> + * @send_data: Send data to the receiver.
> + *
> + * Each supported transport protocol provides its own implementation of
> + * these operations.
> + */
> +struct mhuv3_protocol_ops {
> + int (*rx_startup)(struct mhuv3 *mhu, struct mbox_chan *chan);
> + void (*rx_shutdown)(struct mhuv3 *mhu, struct mbox_chan *chan);
> + void *(*read_data)(struct mhuv3 *mhu, struct mbox_chan *chan);
> + void (*rx_complete)(struct mhuv3 *mhu, struct mbox_chan *chan);
> + void (*tx_startup)(struct mhuv3 *mhu, struct mbox_chan *chan);
> + void (*tx_shutdown)(struct mhuv3 *mhu, struct mbox_chan *chan);
> + int (*last_tx_done)(struct mhuv3 *mhu, struct mbox_chan *chan);
> + int (*send_data)(struct mhuv3 *mhu, struct mbox_chan *chan, void *arg);
> +};
> +
> +/**
> + * struct mhuv3_mbox_chan_priv - MHUv3 channel private information
> + *
> + * @ch_idx: Channel window index associated to this mailbox channel.
> + * @doorbell: Doorbell bit number within the @ch_idx window.
> + * Only relevant to Doorbell transport.
> + * @ops: Transport protocol specific operations for this channel.
> + *
> + * Transport specific data attached to mmailbox channel priv data.
> + */
> +struct mhuv3_mbox_chan_priv {
> + u32 ch_idx;
> + u32 doorbell;
> + const struct mhuv3_protocol_ops *ops;
> +};
> +
> +/**
> + * struct mhuv3_extension - MHUv3 extension descriptor
> + *
> + * @type: Type of extension
> + * @max_chans: Max number of channels found for this extension.
> + * @base_ch_idx: First channel number assigned to this extension, picked from
> + * the set of all mailbox channels descriptors created.
> + * @mbox_of_xlate: Extension specific helper to parse DT and lookup associated
> + * channel from the related 'mboxes' property.
> + * @combined_irq_setup: Extension specific helper to setup the combined irq.
> + * @channels_init: Extension specific helper to initialize channels.
> + * @chan_from_comb_irq_get: Extension specific helper to lookup which channel
> + * triggered the combined irq.
> + * @pending_db: Array of per-channel pending doorbells.
> + * @pending_lock: Protect access to pending_db.
> + */
> +struct mhuv3_extension {
> + enum mhuv3_extension_type type;
> + unsigned int max_chans;
> + unsigned int base_ch_idx;
> + struct mbox_chan *(*mbox_of_xlate)(struct mhuv3 *mhu,
> + unsigned int channel,
> + unsigned int param);
> + void (*combined_irq_setup)(struct mhuv3 *mhu);
> + int (*channels_init)(struct mhuv3 *mhu);
> + struct mbox_chan *(*chan_from_comb_irq_get)(struct mhuv3 *mhu);
> + u32 pending_db[MHUV3_DBCW_MAX];
> + /* Protect access to pending_db */
> + spinlock_t pending_lock;
> +};
> +
> +/**
> + * struct mhuv3 - MHUv3 mailbox controller data
> + *
> + * @frame: Frame type: MBX_FRAME or PBX_FRAME.
> + * @auto_op_full: Flag to indicate if the MHU supports AutoOp full mode.
> + * @major: MHUv3 controller architectural major version.
> + * @minor: MHUv3 controller architectural minor version.
> + * @tot_chans: The total number of channnels discovered across all extensions.
> + * @cmb_irq: Combined IRQ number if any found defined.
> + * @ctrl: A reference to the MHUv3 control page for this block.
> + * @pbx: Base address of the PBX register mapping region.
> + * @mbx: Base address of the MBX register mapping region.
> + * @ext: Array holding descriptors for any found implemented extension.
> + * @mbox: Mailbox controller belonging to the MHU frame.
> + */
> +struct mhuv3 {
> + enum mhuv3_frame frame;
> + bool auto_op_full;
> + unsigned int major;
> + unsigned int minor;
> + unsigned int tot_chans;
>
may be num_chans or chan_count ?
> + int cmb_irq;
> + struct ctrl_page __iomem *ctrl;
> + union {
> + struct mhu3_pbx_frame_reg __iomem *pbx;
> + struct mhu3_mbx_frame_reg __iomem *mbx;
> + };
> + struct mhuv3_extension *ext[MAX_EXT];
> + struct mbox_controller mbox;
> +};
> +
> +#define mhu_from_mbox(_mbox) container_of(_mbox, struct mhuv3, mbox)
> +
> +typedef int (*mhuv3_extension_initializer)(struct mhuv3 *mhu);
> +
> +/* =================== Doorbell transport protocol operations =============== */
> +
> +static void mhuv3_doorbell_tx_startup(struct mhuv3 *mhu, struct mbox_chan *chan)
> +{
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + /* Enable Transfer Acknowledgment events */
> + writel_relaxed_bitfield(0x1, &mhu->pbx->dbcw[priv->ch_idx].int_en, tfr_ack);
> +}
> +
> +static void mhuv3_doorbell_tx_shutdown(struct mhuv3 *mhu, struct mbox_chan *chan)
> +{
> + unsigned long flags;
> + struct mhuv3_extension *e = mhu->ext[DBE_EXT];
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
In order of decreasing line-lengths please everywhere.
> + /* Disable Channel Transfer Ack events */
> + writel_relaxed_bitfield(0x0, &mhu->pbx->dbcw[priv->ch_idx].int_en, tfr_ack);
> +
> + /* Clear Channel Transfer Ack and pending doorbells */
> + writel_relaxed_bitfield(0x1, &mhu->pbx->dbcw[priv->ch_idx].int_clr, tfr_ack);
> + spin_lock_irqsave(&e->pending_lock, flags);
> + e->pending_db[priv->ch_idx] = 0;
> + spin_unlock_irqrestore(&e->pending_lock, flags);
> +}
> +
> +static int mhuv3_doorbell_rx_startup(struct mhuv3 *mhu, struct mbox_chan *chan)
> +{
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + /* Unmask Channel Transfer events */
> + writel_relaxed(BIT(priv->doorbell), &mhu->mbx->dbcw[priv->ch_idx].msk_clr);
> +
> + return 0;
> +}
> +
> +static void mhuv3_doorbell_rx_shutdown(struct mhuv3 *mhu,
> + struct mbox_chan *chan)
> +{
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + /* Mask Channel Transfer events */
> + writel_relaxed(BIT(priv->doorbell), &mhu->mbx->dbcw[priv->ch_idx].msk_set);
> +}
> +
> +static void mhuv3_doorbell_rx_complete(struct mhuv3 *mhu, struct mbox_chan *chan)
> +{
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + /* Clearing the pending transfer generates the Channel Transfer Ack */
> + writel_relaxed(BIT(priv->doorbell), &mhu->mbx->dbcw[priv->ch_idx].clr);
> +}
> +
> +static int mhuv3_doorbell_last_tx_done(struct mhuv3 *mhu,
> + struct mbox_chan *chan)
> +{
> + int done;
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + done = !(readl_relaxed(&mhu->pbx->dbcw[priv->ch_idx].st) &
> + BIT(priv->doorbell));
> + if (done) {
> + unsigned long flags;
> + struct mhuv3_extension *e = mhu->ext[DBE_EXT];
> +
> + /* Take care to clear the pending doorbell also when polling */
> + spin_lock_irqsave(&e->pending_lock, flags);
> + e->pending_db[priv->ch_idx] &= ~BIT(priv->doorbell);
> + spin_unlock_irqrestore(&e->pending_lock, flags);
> + }
> +
> + return done;
> +}
> +
> +static int mhuv3_doorbell_send_data(struct mhuv3 *mhu, struct mbox_chan *chan,
> + void *arg)
> +{
> + int ret = 0;
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> + struct mhuv3_extension *e = mhu->ext[DBE_EXT];
> + unsigned long flags;
> +
> + spin_lock_irqsave(&e->pending_lock, flags);
> + /* Only one in-flight Transfer is allowed per-doorbell */
> + if (!(e->pending_db[priv->ch_idx] & BIT(priv->doorbell))) {
> + e->pending_db[priv->ch_idx] |= BIT(priv->doorbell);
> + writel_relaxed(BIT(priv->doorbell),
> + &mhu->pbx->dbcw[priv->ch_idx].set);
> + } else {
> + ret = -EBUSY;
> + }
> + spin_unlock_irqrestore(&e->pending_lock, flags);
> +
> + return ret;
> +}
> +
> +static const struct mhuv3_protocol_ops mhuv3_doorbell_ops = {
> + .tx_startup = mhuv3_doorbell_tx_startup,
> + .tx_shutdown = mhuv3_doorbell_tx_shutdown,
> + .rx_startup = mhuv3_doorbell_rx_startup,
> + .rx_shutdown = mhuv3_doorbell_rx_shutdown,
> + .rx_complete = mhuv3_doorbell_rx_complete,
> + .last_tx_done = mhuv3_doorbell_last_tx_done,
> + .send_data = mhuv3_doorbell_send_data,
> +};
> +
> +/* Sender and receiver mailbox ops */
> +static bool mhuv3_sender_last_tx_done(struct mbox_chan *chan)
> +{
> + struct mhuv3 *mhu = mhu_from_mbox(chan->mbox);
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + return priv->ops->last_tx_done(mhu, chan);
> +}
> +
> +static int mhuv3_sender_send_data(struct mbox_chan *chan, void *data)
> +{
> + struct mhuv3 *mhu = mhu_from_mbox(chan->mbox);
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + if (!priv->ops->last_tx_done(mhu, chan))
> + return -EBUSY;
> +
> + return priv->ops->send_data(mhu, chan, data);
> +}
> +
> +static int mhuv3_sender_startup(struct mbox_chan *chan)
> +{
> + struct mhuv3 *mhu = mhu_from_mbox(chan->mbox);
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + if (priv->ops->tx_startup)
> + priv->ops->tx_startup(mhu, chan);
> +
> + return 0;
> +}
> +
> +static void mhuv3_sender_shutdown(struct mbox_chan *chan)
> +{
> + struct mhuv3 *mhu = mhu_from_mbox(chan->mbox);
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + if (priv->ops->tx_shutdown)
> + priv->ops->tx_shutdown(mhu, chan);
> +}
> +
> +static const struct mbox_chan_ops mhuv3_sender_ops = {
> + .send_data = mhuv3_sender_send_data,
> + .startup = mhuv3_sender_startup,
> + .shutdown = mhuv3_sender_shutdown,
> + .last_tx_done = mhuv3_sender_last_tx_done,
> +};
> +
> +static int mhuv3_receiver_startup(struct mbox_chan *chan)
> +{
> + struct mhuv3 *mhu = mhu_from_mbox(chan->mbox);
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + return priv->ops->rx_startup(mhu, chan);
> +}
> +
> +static void mhuv3_receiver_shutdown(struct mbox_chan *chan)
> +{
> + struct mhuv3 *mhu = mhu_from_mbox(chan->mbox);
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + priv->ops->rx_shutdown(mhu, chan);
> +}
> +
> +static int mhuv3_receiver_send_data(struct mbox_chan *chan, void *data)
> +{
> + dev_err(chan->mbox->dev,
> + "Trying to transmit on a MBX MHUv3 frame\n");
> + return -EIO;
> +}
> +
> +static bool mhuv3_receiver_last_tx_done(struct mbox_chan *chan)
> +{
> + dev_err(chan->mbox->dev, "Trying to Tx poll on a MBX MHUv3 frame\n");
> + return true;
> +}
> +
> +static const struct mbox_chan_ops mhuv3_receiver_ops = {
> + .send_data = mhuv3_receiver_send_data,
> + .startup = mhuv3_receiver_startup,
> + .shutdown = mhuv3_receiver_shutdown,
> + .last_tx_done = mhuv3_receiver_last_tx_done,
> +};
> +
> +static struct mbox_chan *mhuv3_dbe_mbox_of_xlate(struct mhuv3 *mhu,
> + unsigned int channel,
> + unsigned int doorbell)
> +{
> + struct mbox_controller *mbox = &mhu->mbox;
> + struct mbox_chan *chans = mbox->chans;
> + struct mhuv3_extension *e = mhu->ext[DBE_EXT];
> +
> + if (channel >= e->max_chans || doorbell >= MHUV3_STAT_BITS) {
> + dev_err(mbox->dev, "Couldn't xlate to a valid channel (%d: %d)\n",
> + channel, doorbell);
> + return ERR_PTR(-ENODEV);
> + }
> +
> + return &chans[e->base_ch_idx + channel * MHUV3_STAT_BITS + doorbell];
> +}
> +
> +static void mhuv3_dbe_combined_irq_setup(struct mhuv3 *mhu)
> +{
> + int i;
> + struct mhuv3_extension *e = mhu->ext[DBE_EXT];
> +
> + if (mhu->frame == PBX_FRAME) {
> + struct pdbcw_page __iomem *dbcw = mhu->pbx->dbcw;
> +
> + for (i = 0; i < e->max_chans; i++) {
> + writel_relaxed_bitfield(0x1, &dbcw[i].int_clr, tfr_ack);
> + writel_relaxed_bitfield(0x0, &dbcw[i].int_en, tfr_ack);
> + writel_relaxed_bitfield(0x1, &dbcw[i].ctrl, comb_en);
> + }
> + } else {
> + struct mdbcw_page __iomem *dbcw = mhu->mbx->dbcw;
> +
> + for (i = 0; i < e->max_chans; i++) {
> + writel_relaxed(0xFFFFFFFF, &dbcw[i].clr);
> + writel_relaxed(0xFFFFFFFF, &dbcw[i].msk_set);
> + writel_relaxed_bitfield(0x1, &dbcw[i].ctrl, comb_en);
> + }
> + }
> +}
> +
> +static int mhuv3_dbe_channels_init(struct mhuv3 *mhu)
> +{
> + int i;
> + struct mhuv3_extension *e = mhu->ext[DBE_EXT];
> + struct mbox_controller *mbox = &mhu->mbox;
> + struct mbox_chan *chans;
> +
> + chans = mbox->chans + mbox->num_chans;
> + e->base_ch_idx = mbox->num_chans;
> + for (i = 0; i < e->max_chans; i++) {
> + int k;
> + struct mhuv3_mbox_chan_priv *priv;
> +
> + for (k = 0; k < MHUV3_STAT_BITS; k++) {
> + priv = devm_kmalloc(mbox->dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + priv->ch_idx = i;
> + priv->ops = &mhuv3_doorbell_ops;
> + priv->doorbell = k;
> + chans++->con_priv = priv;
> + mbox->num_chans++;
> + }
> + }
> +
> + spin_lock_init(&e->pending_lock);
> +
> + return 0;
> +}
> +
> +static struct mbox_chan *mhuv3_dbe_chan_from_comb_irq_get(struct mhuv3 *mhu)
> +{
> + int i;
> + struct mhuv3_extension *e = mhu->ext[DBE_EXT];
> + struct device *dev = mhu->mbox.dev;
> +
> + for (i = 0; i < MHUV3_DBCH_CMB_INT_ST_REG_CNT; i++) {
> + unsigned int channel, db = MHUV3_INVALID_DOORBELL;
> + u32 cmb_st, st;
> +
> + cmb_st = readl_relaxed(&mhu->ctrl->dbch_int_st[i]);
> + if (!cmb_st)
> + continue;
> +
> + channel = i * MHUV3_STAT_BITS + __builtin_ctz(cmb_st);
__ffs instead of __builtin_ctz please.
> + if (channel >= e->max_chans) {
> + dev_err(dev, "Invalid %s channel:%d\n",
> + mhuv3_str[mhu->frame], channel);
> + break;
> + }
> +
> + if (mhu->frame == PBX_FRAME) {
> + unsigned long flags;
> + u32 active_dbs, fired_dbs;
> +
> + st = readl_relaxed_bitfield(&mhu->pbx->dbcw[channel].int_st,
> + tfr_ack);
> + if (!st) {
> + dev_warn(dev, "Spurios IRQ on %s channel:%d\n",
> + mhuv3_str[mhu->frame], channel);
> + continue;
> + }
> +
> + active_dbs = readl_relaxed(&mhu->pbx->dbcw[channel].st);
> + spin_lock_irqsave(&e->pending_lock, flags);
> + fired_dbs = e->pending_db[channel] & ~active_dbs;
> + if (fired_dbs) {
> + db = __builtin_ctz(fired_dbs);
> + e->pending_db[channel] &= ~BIT(db);
> + fired_dbs &= ~BIT(db);
> + }
> + spin_unlock_irqrestore(&e->pending_lock, flags);
> +
> + /* Clear TFR Ack if no more doorbells pending */
> + if (!fired_dbs)
> + writel_relaxed_bitfield(0x1,
> + &mhu->pbx->dbcw[channel].int_clr,
> + tfr_ack);
> + } else {
> + st = readl_relaxed(&mhu->mbx->dbcw[channel].st_msk);
> + if (!st) {
> + dev_warn(dev, "Spurios IRQ on %s channel:%d\n",
> + mhuv3_str[mhu->frame], channel);
> + continue;
> + }
> + db = __builtin_ctz(st);
> + }
> +
> + if (db != MHUV3_INVALID_DOORBELL) {
> + dev_dbg(dev, "Found %s ch[%d]/db[%d]\n",
> + mhuv3_str[mhu->frame], channel, db);
> +
> + return &mhu->mbox.chans[channel * MHUV3_STAT_BITS + db];
> + }
> + }
> +
> + return ERR_PTR(-EIO);
> +}
> +
> +static int mhuv3_dbe_init(struct mhuv3 *mhu)
> +{
> + struct mhuv3_extension *e;
> + struct device *dev = mhu->mbox.dev;
> +
> + if (!readl_relaxed_bitfield(&mhu->ctrl->feat_spt0, dbe_spt))
> + return 0;
> +
> + dev_dbg(dev, "%s: Initializing DBE Extension.\n", mhuv3_str[mhu->frame]);
> +
> + e = devm_kzalloc(dev, sizeof(*e), GFP_KERNEL);
> + if (!e)
> + return -ENOMEM;
> +
> + e->type = DBE_EXT;
> + /* Note that, by the spec, the number of channels is (num_dbch + 1) */
> + e->max_chans =
> + readl_relaxed_bitfield(&mhu->ctrl->dbch_cfg0, num_dbch) + 1;
> + e->mbox_of_xlate = mhuv3_dbe_mbox_of_xlate;
> + e->combined_irq_setup = mhuv3_dbe_combined_irq_setup;
> + e->channels_init = mhuv3_dbe_channels_init;
> + e->chan_from_comb_irq_get = mhuv3_dbe_chan_from_comb_irq_get;
> +
> + mhu->tot_chans += e->max_chans * MHUV3_STAT_BITS;
> + mhu->ext[DBE_EXT] = e;
> +
> + dev_info(dev, "%s: found %d DBE channels.\n",
> + mhuv3_str[mhu->frame], e->max_chans);
> +
> + return 0;
> +}
> +
> +static int mhuv3_fce_init(struct mhuv3 *mhu)
> +{
> + struct device *dev = mhu->mbox.dev;
> +
> + if (!readl_relaxed_bitfield(&mhu->ctrl->feat_spt0, fce_spt))
> + return 0;
> +
> + dev_dbg(dev, "%s: FCE Extension not supported by driver.\n",
> + mhuv3_str[mhu->frame]);
> +
> + return 0;
> +}
> +
> +static int mhuv3_fe_init(struct mhuv3 *mhu)
> +{
> + struct device *dev = mhu->mbox.dev;
> +
> + if (!readl_relaxed_bitfield(&mhu->ctrl->feat_spt0, fe_spt))
> + return 0;
> +
> + dev_dbg(dev, "%s: FE Extension not supported by driver.\n",
> + mhuv3_str[mhu->frame]);
> +
> + return 0;
> +}
> +
> +static mhuv3_extension_initializer mhuv3_extension_init[MAX_EXT] = {
> + mhuv3_dbe_init,
> + mhuv3_fce_init,
> + mhuv3_fe_init,
> +};
> +
> +static int mhuv3_initialize_channels(struct device *dev, struct mhuv3 *mhu)
> +{
> + int i, ret = 0;
> + struct mbox_controller *mbox = &mhu->mbox;
> +
> + mbox->chans = devm_kcalloc(dev, mhu->tot_chans,
> + sizeof(*mbox->chans), GFP_KERNEL);
> + if (!mbox->chans)
> + return -ENOMEM;
> +
> + for (i = FIRST_EXT; i < MAX_EXT && !ret; i++)
> + if (mhu->ext[i])
> + ret = mhu->ext[i]->channels_init(mhu);
> +
> + return ret;
> +}
> +
> +static struct mbox_chan *mhuv3_mbox_of_xlate(struct mbox_controller *mbox,
> + const struct of_phandle_args *pa)
> +{
> + unsigned int type, channel, param;
> + struct mhuv3 *mhu = mhu_from_mbox(mbox);
> +
> + if (pa->args_count != MHUV3_MBOX_CELLS)
> + return ERR_PTR(-EINVAL);
> +
> + type = pa->args[MHUV3_MBOX_CELL_TYPE];
> + if (type >= MAX_EXT)
> + return ERR_PTR(-EINVAL);
> +
> + channel = pa->args[MHUV3_MBOX_CELL_CHWN];
> + param = pa->args[MHUV3_MBOX_CELL_PARAM];
> +
> + return mhu->ext[type]->mbox_of_xlate(mhu, channel, param);
> +}
> +
> +static int mhuv3_frame_init(struct mhuv3 *mhu, void __iomem *regs)
> +{
> + int i, ret = 0;
> + struct device *dev = mhu->mbox.dev;
> +
> + mhu->ctrl = regs;
> + mhu->frame = readl_relaxed_bitfield(&mhu->ctrl->blk_id, blk_id);
> + if (mhu->frame > MBX_FRAME) {
> + dev_err(dev, "Invalid Frame type- %d\n", mhu->frame);
> + return -EINVAL;
> + }
> +
> + mhu->major = readl_relaxed_bitfield(&mhu->ctrl->aidr, arch_major_rev);
> + mhu->minor = readl_relaxed_bitfield(&mhu->ctrl->aidr, arch_minor_rev);
> + if (mhu->major != MHUV3_MAJOR_VERSION) {
> + dev_warn(dev, "Unsupported MHU %s block - major:%d minor:%d\n",
> + mhuv3_str[mhu->frame], mhu->major, mhu->minor);
> + return -EINVAL;
> + }
> + mhu->auto_op_full = !!readl_relaxed_bitfield(&mhu->ctrl->feat_spt1,
> + auto_op_spt);
> + /* Request the PBX/MBX to remain operational */
> + if (mhu->auto_op_full)
> + writel_relaxed_bitfield(0x1, &mhu->ctrl->ctrl, op_req);
> +
> + dev_dbg(dev, "Found MHU %s block - major:%d minor:%d\n",
> + mhuv3_str[mhu->frame], mhu->major, mhu->minor);
> +
> + if (mhu->frame == PBX_FRAME)
> + mhu->pbx = regs;
> + else
> + mhu->mbx = regs;
> +
> + for (i = FIRST_EXT; i < MAX_EXT && !ret; i++)
> + ret = mhuv3_extension_init[i](mhu);
> +
> + return ret;
> +}
> +
> +static irqreturn_t mhuv3_pbx_comb_interrupt(int irq, void *arg)
> +{
> + int ret = IRQ_NONE;
> + unsigned int i, found = 0;
> + struct mhuv3 *mhu = arg;
> + struct device *dev = mhu->mbox.dev;
> + struct mbox_chan *chan;
> +
> + for (i = FIRST_EXT; i < MAX_EXT; i++) {
> + /* FCE does not participate to the PBX combined */
> + if (i == FCE_EXT || !mhu->ext[i])
> + continue;
> +
> + chan = mhu->ext[i]->chan_from_comb_irq_get(mhu);
> + if (!IS_ERR(chan)) {
>
'continue' for error instead, to have fewer indented lines.
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + found++;
> + if (chan->cl) {
> + mbox_chan_txdone(chan, 0);
> + ret = IRQ_HANDLED;
> + } else {
> + dev_warn(dev,
> + "TX Ack on UNBOUND channel (%u)\n",
> + priv->ch_idx);
> + }
> + }
> + }
> +
> + if (!found)
> + dev_warn_once(dev, "Failed to find channel for the TX interrupt\n");
> +
> + return ret;
> +}
> +
> +static irqreturn_t mhuv3_mbx_comb_interrupt(int irq, void *arg)
> +{
> + int ret = IRQ_NONE;
> + unsigned int i, found = 0;
> + struct mhuv3 *mhu = arg;
> + struct device *dev = mhu->mbox.dev;
> + struct mbox_chan *chan;
> +
> + for (i = FIRST_EXT; i < MAX_EXT; i++) {
> + if (!mhu->ext[i])
> + continue;
> +
> + /* Process any extension which could be source of the IRQ */
> + chan = mhu->ext[i]->chan_from_comb_irq_get(mhu);
> + if (!IS_ERR(chan)) {
'continue' for error instead, to have fewer indented lines.
> + void *data = NULL;
> + struct mhuv3_mbox_chan_priv *priv = chan->con_priv;
> +
> + found++;
> + /* Read and acknowledge optional in-band LE data first. */
> + if (priv->ops->read_data)
> + data = priv->ops->read_data(mhu, chan);
> +
> + if (chan->cl && !IS_ERR(data)) {
> + mbox_chan_received_data(chan, data);
> + ret = IRQ_HANDLED;
> + } else if (!chan->cl) {
> + dev_warn(dev,
> + "RX Data on UNBOUND channel (%u)\n",
> + priv->ch_idx);
> + } else {
> + dev_err(dev, "Failed to read data: %lu\n",
> + PTR_ERR(data));
> + }
> +
> + if (!IS_ERR(data))
> + kfree(data);
> +
> + /*
> + * Acknowledge transfer after any possible optional
> + * out-of-band data has also been retrieved via
> + * mbox_chan_received_data().
> + */
> + if (priv->ops->rx_complete)
> + priv->ops->rx_complete(mhu, chan);
> + }
> + }
> +
> + if (!found)
> + dev_warn_once(dev, "Failed to find channel for the RX interrupt\n");
> +
> + return ret;
> +}
> +
> +static int mhuv3_setup_pbx(struct mhuv3 *mhu)
> +{
> + struct device *dev = mhu->mbox.dev;
> +
> + mhu->mbox.ops = &mhuv3_sender_ops;
> +
> + if (mhu->cmb_irq > 0) {
> + int ret;
> +
> + ret = devm_request_threaded_irq(dev, mhu->cmb_irq, NULL,
> + mhuv3_pbx_comb_interrupt,
> + IRQF_ONESHOT, "mhuv3-pbx", mhu);
> + if (!ret) {
> + int i;
> +
> + mhu->mbox.txdone_irq = true;
> + mhu->mbox.txdone_poll = false;
> +
> + for (i = FIRST_EXT; i < MAX_EXT; i++)
> + if (mhu->ext[i])
> + mhu->ext[i]->combined_irq_setup(mhu);
> +
> + dev_dbg(dev, "MHUv3 PBX IRQs initialized.\n");
> +
> + return 0;
> + }
> +
> + dev_err(dev, "Failed to request PBX IRQ - ret:%d", ret);
> + }
> +
> + dev_info(dev, "Using PBX in Tx polling mode.\n");
> + mhu->mbox.txdone_irq = false;
> + mhu->mbox.txdone_poll = true;
> + mhu->mbox.txpoll_period = 1;
> +
> + return 0;
> +}
> +
> +static int mhuv3_setup_mbx(struct mhuv3 *mhu)
> +{
> + int ret, i;
> + struct device *dev = mhu->mbox.dev;
> +
> + mhu->mbox.ops = &mhuv3_receiver_ops;
> +
> + if (mhu->cmb_irq <= 0) {
> + dev_err(dev, "Missing MBX combined IRQ !\n");
> + return -EINVAL;
> + }
> +
> + ret = devm_request_threaded_irq(dev, mhu->cmb_irq, NULL,
> + mhuv3_mbx_comb_interrupt, IRQF_ONESHOT,
> + "mhuv3-mbx", mhu);
> + if (ret) {
> + dev_err(dev, "Failed to request MBX IRQ - ret:%d\n", ret);
> + return ret;
> + }
> +
> + for (i = FIRST_EXT; i < MAX_EXT; i++)
> + if (mhu->ext[i])
> + mhu->ext[i]->combined_irq_setup(mhu);
> +
> + dev_dbg(dev, "MHUv3 MBX IRQs initialized.\n");
> +
> + return ret;
> +}
> +
> +static int mhuv3_irqs_init(struct mhuv3 *mhu, struct platform_device *pdev)
> +{
> + int ret;
> +
> + dev_dbg(mhu->mbox.dev, "Initializing %s block.\n", mhuv3_str[mhu->frame]);
> +
> + if (mhu->frame == PBX_FRAME) {
> + mhu->cmb_irq = platform_get_irq_byname_optional(pdev, "combined");
> + ret = mhuv3_setup_pbx(mhu);
> + } else {
> + mhu->cmb_irq = platform_get_irq_byname(pdev, "combined");
> + ret = mhuv3_setup_mbx(mhu);
> + }
> +
> + return ret;
> +}
> +
> +static int mhuv3_probe(struct platform_device *pdev)
> +{
> + int ret;
> + struct mhuv3 *mhu;
> + void __iomem *regs;
> + struct device *dev = &pdev->dev;
> +
> + mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL);
> + if (!mhu)
> + return -ENOMEM;
> +
> + regs = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(regs))
> + return PTR_ERR(regs);
> +
> + mhu->mbox.dev = dev;
> + ret = mhuv3_frame_init(mhu, regs);
> + if (ret)
> + return ret;
> +
> + ret = mhuv3_irqs_init(mhu, pdev);
> + if (ret)
> + return ret;
> +
> + mhu->mbox.of_xlate = mhuv3_mbox_of_xlate;
> + ret = mhuv3_initialize_channels(dev, mhu);
> + if (ret)
> + return ret;
> +
> + ret = devm_mbox_controller_register(dev, &mhu->mbox);
> + if (ret)
> + dev_err(dev, "failed to register ARM MHUv3 driver %d\n", ret);
> +
> + platform_set_drvdata(pdev, mhu);
> +
> + return ret;
> +}
> +
> +static int mhuv3_remove(struct platform_device *pdev)
> +{
> + struct mhuv3 *mhu = platform_get_drvdata(pdev);
> +
> + if (mhu->auto_op_full)
> + writel_relaxed_bitfield(0x0, &mhu->ctrl->ctrl, op_req);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id mhuv3_of_match[] = {
> + { .compatible = "arm,mhuv3", .data = NULL },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, mhuv3_of_match);
> +
> +static struct platform_driver mhuv3_driver = {
> + .driver = {
> + .name = "arm-mhuv3-mailbox",
> + .of_match_table = mhuv3_of_match,
> + },
> + .probe = mhuv3_probe,
> + .remove = mhuv3_remove,
> +};
> +module_platform_driver(mhuv3_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("ARM MHUv3 Driver");
> +MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>");
> --
> 2.34.1
>
^ permalink raw reply
* RE: [PATCH v4 5/7] PCI: dwc: rcar-gen4: Add .ltssm_enable() for other SoC support
From: Yoshihiro Shimoda @ 2024-04-08 1:11 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: lpieralisi@kernel.org, kw@linux.com, robh@kernel.org,
bhelgaas@google.com, krzysztof.kozlowski+dt@linaro.org,
conor+dt@kernel.org, jingoohan1@gmail.com, mani@kernel.org,
marek.vasut+renesas@gmail.com, linux-pci@vger.kernel.org,
devicetree@vger.kernel.org, linux-renesas-soc@vger.kernel.org
In-Reply-To: <CAMuHMdUbKgqFr93x+0PCzGrRyW2bL69oTp+zsZ2SZ8mh0Fk36g@mail.gmail.com>
Hi Geert-san,
> From: Geert Uytterhoeven, Sent: Friday, April 5, 2024 11:13 PM
>
> Hi Shimoda-san,
>
> On Wed, Apr 3, 2024 at 7:33 AM Yoshihiro Shimoda
> <yoshihiro.shimoda.uh@renesas.com> wrote:
> > This driver can reuse other R-Car Gen4 SoCs support like r8a779g0 and
> > r8a779h0. However, r8a779g0 and r8a779h0 require other initializing
> > settings that differ than r8a779f0. So, add a new function pointer
> > .ltssm_enable() for it. No behavior changes.
> >
> > After applied this patch, probing SoCs by rcar_gen4_pcie_of_match[]
> > will be changed like below:
> >
> > - r8a779f0 as "renesas,r8a779f0-pcie" and "renesas,r8a779f0-pcie-ep"
> >
> > Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
>
> Thanks for your patch!
Thank you for your review!
> > --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> > +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
>
> > @@ -513,6 +536,14 @@ static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie_ep = {
> > };
> >
> > static const struct of_device_id rcar_gen4_pcie_of_match[] = {
> > + {
> > + .compatible = "renesas,r8a779f0-pcie",
> > + .data = &platdata_r8a779f0_pcie,
> > + },
> > + {
> > + .compatible = "renesas,r8a779f04-pcie-ep",
>
> renesas,r8a779f0-pcie-ep
Oops. I'll fix it.
Best regards,
Yoshihiro Shimoda
> > + .data = &platdata_r8a779f0_pcie_ep,
> > + },
> > {
> > .compatible = "renesas,rcar-gen4-pcie",
> > .data = &platdata_rcar_gen4_pcie,
>
> Gr{oetje,eeting}s,
>
> Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
> -- Linus Torvalds
^ permalink raw reply
* Re: [RFC PATCH v2 4/5] clk: meson: a1: add the audio clock controller driver
From: Jan Dakinevich @ 2024-04-08 1:07 UTC (permalink / raw)
To: Jerome Brunet
Cc: Neil Armstrong, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Kevin Hilman,
Martin Blumenstingl, Philipp Zabel, linux-amlogic, linux-clk,
devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <1j34s3iy9c.fsf@starbuckisacylon.baylibre.com>
On 4/2/24 18:11, Jerome Brunet wrote:
>
> On Thu 28 Mar 2024 at 04:08, Jan Dakinevich <jan.dakinevich@salutedevices.com> wrote:
>
>> This controller provides clocks and reset functionality for audio
>> peripherals on Amlogic A1 SoC family.
>>
>> The driver is almost identical to 'axg-audio', however it would be better
>> to keep it separate due to following reasons:
>>
>> - significant amount of bits has another definition. I will bring there
>> a mess of new defines with A1_ suffixes.
>>
>> - registers of this controller are located in two separate regions. It
>> will give a lot of complications for 'axg-audio' to support this.
>>
>> Signed-off-by: Jan Dakinevich <jan.dakinevich@salutedevices.com>
>> ---
>> drivers/clk/meson/Kconfig | 13 +
>> drivers/clk/meson/Makefile | 1 +
>> drivers/clk/meson/a1-audio.c | 624 +++++++++++++++++++++++++++++++++++
>> drivers/clk/meson/a1-audio.h | 45 +++
>> 4 files changed, 683 insertions(+)
>> create mode 100644 drivers/clk/meson/a1-audio.c
>> create mode 100644 drivers/clk/meson/a1-audio.h
>>
>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>> index d6a2fa5f7e88..80c4a18c83d2 100644
>> --- a/drivers/clk/meson/Kconfig
>> +++ b/drivers/clk/meson/Kconfig
>> @@ -133,6 +133,19 @@ config COMMON_CLK_A1_PERIPHERALS
>> device, A1 SoC Family. Say Y if you want A1 Peripherals clock
>> controller to work.
>>
>> +config COMMON_CLK_A1_AUDIO
>> + tristate "Amlogic A1 SoC Audio clock controller support"
>> + depends on ARM64
>> + select COMMON_CLK_MESON_REGMAP
>> + select COMMON_CLK_MESON_CLKC_UTILS
>> + select COMMON_CLK_MESON_PHASE
>> + select COMMON_CLK_MESON_SCLK_DIV
>> + select COMMON_CLK_MESON_AUDIO_RSTC
>> + help
>> + Support for the Audio clock controller on Amlogic A113L based
>> + device, A1 SoC Family. Say Y if you want A1 Audio clock controller
>> + to work.
>> +
>> config COMMON_CLK_G12A
>> tristate "G12 and SM1 SoC clock controllers support"
>> depends on ARM64
>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>> index 88d94921a4dc..4968fc7ad555 100644
>> --- a/drivers/clk/meson/Makefile
>> +++ b/drivers/clk/meson/Makefile
>> @@ -20,6 +20,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>> obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>> obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
>> obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
>> +obj-$(CONFIG_COMMON_CLK_A1_AUDIO) += a1-audio.o
>> obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>> obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
>> obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o
>> diff --git a/drivers/clk/meson/a1-audio.c b/drivers/clk/meson/a1-audio.c
>> new file mode 100644
>> index 000000000000..bd2b6dde75d4
>> --- /dev/null
>> +++ b/drivers/clk/meson/a1-audio.c
>> @@ -0,0 +1,624 @@
>> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
>> +/*
>> + * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
>> + *
>> + * Author: Jan Dakinevich <jan.dakinevich@salutedevices.com>
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/init.h>
>> +#include <linux/of_device.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regmap.h>
>> +#include <linux/reset.h>
>> +#include <linux/reset-controller.h>
>> +#include <linux/slab.h>
>> +
>> +#include "meson-clkc-utils.h"
>> +#include "meson-audio-rstc.h"
>> +#include "meson-audio.h"
>> +#include "clk-regmap.h"
>> +#include "clk-phase.h"
>> +#include "sclk-div.h"
>> +#include "a1-audio.h"
>> +
>> +static const struct clk_parent_data a1_pclk_pdata[] = {
>> + { .fw_name = "pclk" },
>> +};
>
> Shouldn't you go through AUD2_CLKID_AUDIOTOP instead ?
>
>> +
>> +#define AUD_PCLK_GATE(_name, _reg, _bit) { \
>> + .data = &(struct clk_regmap_gate_data){ \
>> + .offset = (_reg), \
>> + .bit_idx = (_bit), \
>> + }, \
>> + .hw.init = &(struct clk_init_data) { \
>> + .name = "aud_"#_name, \
>> + .ops = &clk_regmap_gate_ops, \
>> + .parent_data = a1_pclk_pdata, \
>> + .num_parents = 1, \
>> + }, \
>> +}
>> +
>> +struct clk_regmap aud_ddr_arb =
>> + AUD_PCLK_GATE(ddr_arb, AUDIO_CLK_GATE_EN0, 0);
>> +struct clk_regmap aud_tdmin_a =
>> + AUD_PCLK_GATE(tdmin_a, AUDIO_CLK_GATE_EN0, 1);
>> +struct clk_regmap aud_tdmin_b =
>> + AUD_PCLK_GATE(tdmin_b, AUDIO_CLK_GATE_EN0, 2);
>> +struct clk_regmap aud_tdmin_lb =
>> + AUD_PCLK_GATE(tdmin_lb, AUDIO_CLK_GATE_EN0, 3);
>> +struct clk_regmap aud_loopback =
>> + AUD_PCLK_GATE(loopback, AUDIO_CLK_GATE_EN0, 4);
>> +struct clk_regmap aud_tdmout_a =
>> + AUD_PCLK_GATE(tdmout_a, AUDIO_CLK_GATE_EN0, 5);
>> +struct clk_regmap aud_tdmout_b =
>> + AUD_PCLK_GATE(tdmout_b, AUDIO_CLK_GATE_EN0, 6);
>> +struct clk_regmap aud_frddr_a =
>> + AUD_PCLK_GATE(frddr_a, AUDIO_CLK_GATE_EN0, 7);
>> +struct clk_regmap aud_frddr_b =
>> + AUD_PCLK_GATE(frddr_b, AUDIO_CLK_GATE_EN0, 8);
>> +struct clk_regmap aud_toddr_a =
>> + AUD_PCLK_GATE(toddr_a, AUDIO_CLK_GATE_EN0, 9);
>> +struct clk_regmap aud_toddr_b =
>> + AUD_PCLK_GATE(toddr_b, AUDIO_CLK_GATE_EN0, 10);
>> +struct clk_regmap aud_spdifin =
>> + AUD_PCLK_GATE(spdifin, AUDIO_CLK_GATE_EN0, 11);
>> +struct clk_regmap aud_resample =
>> + AUD_PCLK_GATE(resample, AUDIO_CLK_GATE_EN0, 12);
>> +struct clk_regmap aud_eqdrc =
>> + AUD_PCLK_GATE(eqdrc, AUDIO_CLK_GATE_EN0, 13);
>> +struct clk_regmap aud_audiolocker =
>> + AUD_PCLK_GATE(audiolocker, AUDIO_CLK_GATE_EN0, 14);
>> +
>> +struct clk_regmap aud2_ddr_arb =
>> + AUD_PCLK_GATE(2_ddr_arb, AUDIO2_CLK_GATE_EN0, 0);
>> +struct clk_regmap aud2_pdm =
>> + AUD_PCLK_GATE(2_pdm, AUDIO2_CLK_GATE_EN0, 1);
>> +struct clk_regmap aud2_tdmin_vad =
>> + AUD_PCLK_GATE(2_tdmin_vad, AUDIO2_CLK_GATE_EN0, 2);
>> +struct clk_regmap aud2_toddr_vad =
>> + AUD_PCLK_GATE(2_toddr_vad, AUDIO2_CLK_GATE_EN0, 3);
>> +struct clk_regmap aud2_vad =
>> + AUD_PCLK_GATE(2_vad, AUDIO2_CLK_GATE_EN0, 4);
>> +struct clk_regmap aud2_audiotop =
>> + AUD_PCLK_GATE(2_audiotop, AUDIO2_CLK_GATE_EN0, 7);
>> +
>> +static const struct clk_parent_data a1_mst_pdata[] = {
>> + { .fw_name = "dds_in" },
>> + { .fw_name = "fclk_div2" },
>> + { .fw_name = "fclk_div3" },
>> + { .fw_name = "hifi_pll" },
>> + { .fw_name = "xtal" },
>> +};
>> +
>> +#define AUD_MST_MCLK_MUX(_name, _reg) \
>> + AUD_MUX(_name##_sel, _reg, 0x7, 24, CLK_MUX_ROUND_CLOSEST, \
>> + a1_mst_pdata, 0)
>> +#define AUD_MST_MCLK_DIV(_name, _reg) \
>> + AUD_DIV(_name##_div, _reg, 0, 16, CLK_DIVIDER_ROUND_CLOSEST, \
>> + aud_##_name##_sel, CLK_SET_RATE_PARENT)
>> +#define AUD_MST_MCLK_GATE(_name, _reg) \
>> + AUD_GATE(_name, _reg, 31, aud_##_name##_div, \
>> + CLK_SET_RATE_PARENT)
>> +
>> +struct clk_regmap aud_mst_a_mclk_mux =
>> + AUD_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL);
>> +struct clk_regmap aud_mst_a_mclk_div =
>> + AUD_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL);
>> +struct clk_regmap aud_mst_a_mclk =
>> + AUD_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL);
>> +
>> +struct clk_regmap aud_mst_b_mclk_mux =
>> + AUD_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL);
>> +struct clk_regmap aud_mst_b_mclk_div =
>> + AUD_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL);
>> +struct clk_regmap aud_mst_b_mclk =
>> + AUD_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL);
>> +
>> +struct clk_regmap aud_mst_c_mclk_mux =
>> + AUD_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL);
>> +struct clk_regmap aud_mst_c_mclk_div =
>> + AUD_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL);
>> +struct clk_regmap aud_mst_c_mclk =
>> + AUD_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL);
>> +
>> +struct clk_regmap aud_mst_d_mclk_mux =
>> + AUD_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL);
>> +struct clk_regmap aud_mst_d_mclk_div =
>> + AUD_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL);
>> +struct clk_regmap aud_mst_d_mclk =
>> + AUD_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL);
>> +
>> +struct clk_regmap aud_spdifin_clk_mux =
>> + AUD_MST_MCLK_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
>> +struct clk_regmap aud_spdifin_clk_div =
>> + AUD_MST_MCLK_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
>> +struct clk_regmap aud_spdifin_clk =
>> + AUD_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL);
>> +
>> +struct clk_regmap aud_eqdrc_clk_mux =
>> + AUD_MST_MCLK_MUX(eqdrc_clk, AUDIO_CLK_EQDRC_CTRL);
>> +struct clk_regmap aud_eqdrc_clk_div =
>> + AUD_MST_MCLK_DIV(eqdrc_clk, AUDIO_CLK_EQDRC_CTRL);
>> +struct clk_regmap aud_eqdrc_clk =
>> + AUD_MST_MCLK_GATE(eqdrc_clk, AUDIO_CLK_EQDRC_CTRL);
>> +
>> +struct clk_regmap aud_resample_clk_mux =
>> + AUD_MUX(resample_clk_sel, AUDIO_CLK_RESAMPLE_CTRL, 0xf, 24,
>> + CLK_MUX_ROUND_CLOSEST, a1_mst_pdata, CLK_SET_RATE_PARENT);
>> +struct clk_regmap aud_resample_clk_div =
>> + AUD_DIV(resample_clk_div, AUDIO_CLK_RESAMPLE_CTRL, 0, 8,
>> + CLK_DIVIDER_ROUND_CLOSEST, resample_clk_sel, CLK_SET_RATE_PARENT);
>> +struct clk_regmap aud_resample_clk =
>> + AUD_GATE(resample_clk, AUDIO_CLK_RESAMPLE_CTRL, 31,
>> + resample_clk_div, CLK_SET_RATE_PARENT);
>> +
>> +struct clk_regmap aud_locker_in_clk_mux =
>> + AUD_MUX(locker_in_clk_sel, AUDIO_CLK_LOCKER_CTRL, 0xf, 8,
>> + CLK_MUX_ROUND_CLOSEST, a1_mst_pdata, CLK_SET_RATE_PARENT);
>> +struct clk_regmap aud_locker_in_clk_div =
>> + AUD_DIV(locker_in_clk_div, AUDIO_CLK_LOCKER_CTRL, 0, 8,
>> + CLK_DIVIDER_ROUND_CLOSEST, locker_in_clk_sel, CLK_SET_RATE_PARENT);
>> +struct clk_regmap aud_locker_in_clk =
>> + AUD_GATE(locker_in_clk, AUDIO_CLK_LOCKER_CTRL, 15,
>> + locker_in_clk_div, CLK_SET_RATE_PARENT);
>> +
>> +struct clk_regmap aud_locker_out_clk_mux =
>> + AUD_MUX(locker_out_clk_sel, AUDIO_CLK_LOCKER_CTRL, 0xf, 24,
>> + CLK_MUX_ROUND_CLOSEST, a1_mst_pdata, CLK_SET_RATE_PARENT);
>> +struct clk_regmap aud_locker_out_clk_div =
>> + AUD_DIV(locker_out_clk_div, AUDIO_CLK_LOCKER_CTRL, 16, 8,
>> + CLK_DIVIDER_ROUND_CLOSEST, locker_out_clk_sel, CLK_SET_RATE_PARENT);
>> +struct clk_regmap aud_locker_out_clk =
>> + AUD_GATE(locker_out_clk, AUDIO_CLK_LOCKER_CTRL, 31,
>> + locker_out_clk_div, CLK_SET_RATE_PARENT);
>> +
>> +struct clk_regmap aud2_vad_mclk_mux =
>> + AUD_MST_MCLK_MUX(2_vad_mclk, AUDIO2_MCLK_VAD_CTRL);
>> +struct clk_regmap aud2_vad_mclk_div =
>> + AUD_MST_MCLK_DIV(2_vad_mclk, AUDIO2_MCLK_VAD_CTRL);
>> +struct clk_regmap aud2_vad_mclk =
>> + AUD_MST_MCLK_GATE(2_vad_mclk, AUDIO2_MCLK_VAD_CTRL);
>> +
>> +struct clk_regmap aud2_vad_clk_mux =
>> + AUD_MST_MCLK_MUX(2_vad_clk, AUDIO2_CLK_VAD_CTRL);
>> +struct clk_regmap aud2_vad_clk_div =
>> + AUD_MST_MCLK_DIV(2_vad_clk, AUDIO2_CLK_VAD_CTRL);
>> +struct clk_regmap aud2_vad_clk =
>> + AUD_MST_MCLK_GATE(2_vad_clk, AUDIO2_CLK_VAD_CTRL);
>> +
>> +struct clk_regmap aud2_pdm_dclk_mux =
>> + AUD_MST_MCLK_MUX(2_pdm_dclk, AUDIO2_CLK_PDMIN_CTRL0);
>> +struct clk_regmap aud2_pdm_dclk_div =
>> + AUD_MST_MCLK_DIV(2_pdm_dclk, AUDIO2_CLK_PDMIN_CTRL0);
>> +struct clk_regmap aud2_pdm_dclk =
>> + AUD_MST_MCLK_GATE(2_pdm_dclk, AUDIO2_CLK_PDMIN_CTRL0);
>> +
>> +struct clk_regmap aud2_pdm_sysclk_mux =
>> + AUD_MST_MCLK_MUX(2_pdm_sysclk, AUDIO2_CLK_PDMIN_CTRL1);
>> +struct clk_regmap aud2_pdm_sysclk_div =
>> + AUD_MST_MCLK_DIV(2_pdm_sysclk, AUDIO2_CLK_PDMIN_CTRL1);
>> +struct clk_regmap aud2_pdm_sysclk =
>> + AUD_MST_MCLK_GATE(2_pdm_sysclk, AUDIO2_CLK_PDMIN_CTRL1);
>> +
>> +#define AUD_MST_SCLK_PRE_EN(_name, _reg, _pname) \
>> + AUD_GATE(_name##_pre_en, _reg, 31, \
>> + aud_##_pname, 0)
>> +#define AUD_MST_SCLK_DIV(_name, _reg) \
>> + AUD_SCLK_DIV(_name##_div, _reg, 20, 10, 0, 0, \
>> + aud_##_name##_pre_en, CLK_SET_RATE_PARENT)
>> +#define AUD_MST_SCLK_POST_EN(_name, _reg) \
>> + AUD_GATE(_name##_post_en, _reg, 30, \
>> + aud_##_name##_div, CLK_SET_RATE_PARENT)
>> +#define AUD_MST_SCLK(_name, _reg) \
>> + AUD_TRIPHASE(_name, _reg, 1, 0, 2, 4, \
>> + aud_##_name##_post_en, CLK_SET_RATE_PARENT)
>> +
>> +struct clk_regmap aud_mst_a_sclk_pre_en =
>> + AUD_MST_SCLK_PRE_EN(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL0, mst_a_mclk);
>> +struct clk_regmap aud_mst_a_sclk_div =
>> + AUD_MST_SCLK_DIV(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_a_sclk_post_en =
>> + AUD_MST_SCLK_POST_EN(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_a_sclk =
>> + AUD_MST_SCLK(mst_a_sclk, AUDIO_MST_A_SCLK_CTRL1);
>> +
>> +struct clk_regmap aud_mst_b_sclk_pre_en =
>> + AUD_MST_SCLK_PRE_EN(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL0, mst_b_mclk);
>> +struct clk_regmap aud_mst_b_sclk_div =
>> + AUD_MST_SCLK_DIV(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_b_sclk_post_en =
>> + AUD_MST_SCLK_POST_EN(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_b_sclk =
>> + AUD_MST_SCLK(mst_b_sclk, AUDIO_MST_B_SCLK_CTRL1);
>> +
>> +struct clk_regmap aud_mst_c_sclk_pre_en =
>> + AUD_MST_SCLK_PRE_EN(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL0, mst_c_mclk);
>> +struct clk_regmap aud_mst_c_sclk_div =
>> + AUD_MST_SCLK_DIV(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_c_sclk_post_en =
>> + AUD_MST_SCLK_POST_EN(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_c_sclk =
>> + AUD_MST_SCLK(mst_c_sclk, AUDIO_MST_C_SCLK_CTRL1);
>> +
>> +struct clk_regmap aud_mst_d_sclk_pre_en =
>> + AUD_MST_SCLK_PRE_EN(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL0, mst_d_mclk);
>> +struct clk_regmap aud_mst_d_sclk_div =
>> + AUD_MST_SCLK_DIV(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_d_sclk_post_en =
>> + AUD_MST_SCLK_POST_EN(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL0);
>> +struct clk_regmap aud_mst_d_sclk =
>> + AUD_MST_SCLK(mst_d_sclk, AUDIO_MST_D_SCLK_CTRL1);
>> +
>> +#define AUD_MST_LRCLK_DIV(_name, _reg, _pname) \
>> + AUD_SCLK_DIV(_name##_div, _reg, 0, 10, 10, 10, \
>> + aud_##_pname, 0)
>> +#define AUD_MST_LRCLK(_name, _reg) \
>> + AUD_TRIPHASE(_name, _reg, 1, 1, 3, 5, \
>> + aud_##_name##_div, CLK_SET_RATE_PARENT)
>> +
>> +struct clk_regmap aud_mst_a_lrclk_div =
>> + AUD_MST_LRCLK_DIV(mst_a_lrclk, AUDIO_MST_A_SCLK_CTRL0, mst_a_sclk_post_en);
>> +struct clk_regmap aud_mst_a_lrclk =
>> + AUD_MST_LRCLK(mst_a_lrclk, AUDIO_MST_A_SCLK_CTRL1);
>> +
>> +struct clk_regmap aud_mst_b_lrclk_div =
>> + AUD_MST_LRCLK_DIV(mst_b_lrclk, AUDIO_MST_B_SCLK_CTRL0, mst_b_sclk_post_en);
>> +struct clk_regmap aud_mst_b_lrclk =
>> + AUD_MST_LRCLK(mst_b_lrclk, AUDIO_MST_B_SCLK_CTRL1);
>> +
>> +struct clk_regmap aud_mst_c_lrclk_div =
>> + AUD_MST_LRCLK_DIV(mst_c_lrclk, AUDIO_MST_C_SCLK_CTRL0, mst_c_sclk_post_en);
>> +struct clk_regmap aud_mst_c_lrclk =
>> + AUD_MST_LRCLK(mst_c_lrclk, AUDIO_MST_C_SCLK_CTRL1);
>> +
>> +struct clk_regmap aud_mst_d_lrclk_div =
>> + AUD_MST_LRCLK_DIV(mst_d_lrclk, AUDIO_MST_D_SCLK_CTRL0, mst_d_sclk_post_en);
>> +struct clk_regmap aud_mst_d_lrclk =
>> + AUD_MST_LRCLK(mst_d_lrclk, AUDIO_MST_D_SCLK_CTRL1);
>> +
>> +static const struct clk_parent_data a1_mst_sclk_pdata[] = {
>> + { .hw = &aud_mst_a_sclk.hw, .index = -1 },
>> + { .hw = &aud_mst_b_sclk.hw, .index = -1 },
>> + { .hw = &aud_mst_c_sclk.hw, .index = -1 },
>> + { .hw = &aud_mst_d_sclk.hw, .index = -1 },
>> + { .fw_name = "slv_sclk0" },
>> + { .fw_name = "slv_sclk1" },
>> + { .fw_name = "slv_sclk2" },
>> + { .fw_name = "slv_sclk3" },
>> + { .fw_name = "slv_sclk4" },
>> + { .fw_name = "slv_sclk5" },
>> + { .fw_name = "slv_sclk6" },
>> + { .fw_name = "slv_sclk7" },
>> + { .fw_name = "slv_sclk8" },
>> + { .fw_name = "slv_sclk9" },
>> +};
>> +
>> +static const struct clk_parent_data a1_mst_lrclk_pdata[] = {
>> + { .hw = &aud_mst_a_lrclk.hw, .index = -1 },
>> + { .hw = &aud_mst_b_lrclk.hw, .index = -1 },
>> + { .hw = &aud_mst_c_lrclk.hw, .index = -1 },
>> + { .hw = &aud_mst_d_lrclk.hw, .index = -1 },
>> + { .fw_name = "slv_lrclk0" },
>> + { .fw_name = "slv_lrclk1" },
>> + { .fw_name = "slv_lrclk2" },
>> + { .fw_name = "slv_lrclk3" },
>> + { .fw_name = "slv_lrclk4" },
>> + { .fw_name = "slv_lrclk5" },
>> + { .fw_name = "slv_lrclk6" },
>> + { .fw_name = "slv_lrclk7" },
>> + { .fw_name = "slv_lrclk8" },
>> + { .fw_name = "slv_lrclk9" },
>> +};
>> +
>> +#define AUD_TDM_SCLK_MUX(_name, _reg) \
>> + AUD_MUX(_name##_sel, _reg, 0xf, 24, \
>> + CLK_MUX_ROUND_CLOSEST, a1_mst_sclk_pdata, 0)
>> +#define AUD_TDM_SCLK_PRE_EN(_name, _reg) \
>> + AUD_GATE(_name##_pre_en, _reg, 31, \
>> + aud_##_name##_sel, CLK_SET_RATE_PARENT)
>> +#define AUD_TDM_SCLK_POST_EN(_name, _reg) \
>> + AUD_GATE(_name##_post_en, _reg, 30, \
>> + aud_##_name##_pre_en, CLK_SET_RATE_PARENT)
>> +#define AUD_TDM_SCLK_WS(_name, _reg) \
>> + AUD_SCLK_WS(_name, _reg, 1, 29, 28, \
>> + aud_##_name##_post_en, \
>> + CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT)
>> +
>> +#define AUD_TDM_LRLCK(_name, _reg) \
>> + AUD_MUX(_name, _reg, 0xf, 20, \
>> + CLK_MUX_ROUND_CLOSEST, a1_mst_lrclk_pdata, \
>> + CLK_SET_RATE_PARENT)
>> +
>> +struct clk_regmap aud_tdmin_a_sclk_mux =
>> + AUD_TDM_SCLK_MUX(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
>> +struct clk_regmap aud_tdmin_a_sclk_pre_en =
>> + AUD_TDM_SCLK_PRE_EN(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
>> +struct clk_regmap aud_tdmin_a_sclk_post_en =
>> + AUD_TDM_SCLK_POST_EN(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
>> +struct clk_regmap aud_tdmin_a_sclk =
>> + AUD_TDM_SCLK_WS(tdmin_a_sclk, AUDIO_CLK_TDMIN_A_CTRL);
>> +struct clk_regmap aud_tdmin_a_lrclk =
>> + AUD_TDM_LRLCK(tdmin_a_lrclk, AUDIO_CLK_TDMIN_A_CTRL);
>> +
>> +struct clk_regmap aud_tdmin_b_sclk_mux =
>> + AUD_TDM_SCLK_MUX(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
>> +struct clk_regmap aud_tdmin_b_sclk_pre_en =
>> + AUD_TDM_SCLK_PRE_EN(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
>> +struct clk_regmap aud_tdmin_b_sclk_post_en =
>> + AUD_TDM_SCLK_POST_EN(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
>> +struct clk_regmap aud_tdmin_b_sclk =
>> + AUD_TDM_SCLK_WS(tdmin_b_sclk, AUDIO_CLK_TDMIN_B_CTRL);
>> +struct clk_regmap aud_tdmin_b_lrclk =
>> + AUD_TDM_LRLCK(tdmin_b_lrclk, AUDIO_CLK_TDMIN_B_CTRL);
>> +
>> +struct clk_regmap aud_tdmin_lb_sclk_mux =
>> + AUD_TDM_SCLK_MUX(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
>> +struct clk_regmap aud_tdmin_lb_sclk_pre_en =
>> + AUD_TDM_SCLK_PRE_EN(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
>> +struct clk_regmap aud_tdmin_lb_sclk_post_en =
>> + AUD_TDM_SCLK_POST_EN(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
>> +struct clk_regmap aud_tdmin_lb_sclk =
>> + AUD_TDM_SCLK_WS(tdmin_lb_sclk, AUDIO_CLK_TDMIN_LB_CTRL);
>> +struct clk_regmap aud_tdmin_lb_lrclk =
>> + AUD_TDM_LRLCK(tdmin_lb_lrclk, AUDIO_CLK_TDMIN_LB_CTRL);
>> +
>> +struct clk_regmap aud_tdmout_a_sclk_mux =
>> + AUD_TDM_SCLK_MUX(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
>> +struct clk_regmap aud_tdmout_a_sclk_pre_en =
>> + AUD_TDM_SCLK_PRE_EN(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
>> +struct clk_regmap aud_tdmout_a_sclk_post_en =
>> + AUD_TDM_SCLK_POST_EN(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
>> +struct clk_regmap aud_tdmout_a_sclk =
>> + AUD_TDM_SCLK_WS(tdmout_a_sclk, AUDIO_CLK_TDMOUT_A_CTRL);
>> +struct clk_regmap aud_tdmout_a_lrclk =
>> + AUD_TDM_LRLCK(tdmout_a_lrclk, AUDIO_CLK_TDMOUT_A_CTRL);
>> +
>> +struct clk_regmap aud_tdmout_b_sclk_mux =
>> + AUD_TDM_SCLK_MUX(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
>> +struct clk_regmap aud_tdmout_b_sclk_pre_en =
>> + AUD_TDM_SCLK_PRE_EN(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
>> +struct clk_regmap aud_tdmout_b_sclk_post_en =
>> + AUD_TDM_SCLK_POST_EN(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
>> +struct clk_regmap aud_tdmout_b_sclk =
>> + AUD_TDM_SCLK_WS(tdmout_b_sclk, AUDIO_CLK_TDMOUT_B_CTRL);
>> +struct clk_regmap aud_tdmout_b_lrclk =
>> + AUD_TDM_LRLCK(tdmout_b_lrclk, AUDIO_CLK_TDMOUT_B_CTRL);
>> +
>> +static struct clk_hw *a1_audio_hw_clks[] = {
>> + [AUD_CLKID_DDR_ARB] = &aud_ddr_arb.hw,
>> + [AUD_CLKID_TDMIN_A] = &aud_tdmin_a.hw,
>> + [AUD_CLKID_TDMIN_B] = &aud_tdmin_b.hw,
>> + [AUD_CLKID_TDMIN_LB] = &aud_tdmin_lb.hw,
>> + [AUD_CLKID_LOOPBACK] = &aud_loopback.hw,
>> + [AUD_CLKID_TDMOUT_A] = &aud_tdmout_a.hw,
>> + [AUD_CLKID_TDMOUT_B] = &aud_tdmout_b.hw,
>> + [AUD_CLKID_FRDDR_A] = &aud_frddr_a.hw,
>> + [AUD_CLKID_FRDDR_B] = &aud_frddr_b.hw,
>> + [AUD_CLKID_TODDR_A] = &aud_toddr_a.hw,
>> + [AUD_CLKID_TODDR_B] = &aud_toddr_b.hw,
>> + [AUD_CLKID_SPDIFIN] = &aud_spdifin.hw,
>> + [AUD_CLKID_RESAMPLE] = &aud_resample.hw,
>> + [AUD_CLKID_EQDRC] = &aud_eqdrc.hw,
>> + [AUD_CLKID_LOCKER] = &aud_audiolocker.hw,
>> + [AUD_CLKID_MST_A_MCLK_SEL] = &aud_mst_a_mclk_mux.hw,
>> + [AUD_CLKID_MST_A_MCLK_DIV] = &aud_mst_a_mclk_div.hw,
>> + [AUD_CLKID_MST_A_MCLK] = &aud_mst_a_mclk.hw,
>> + [AUD_CLKID_MST_B_MCLK_SEL] = &aud_mst_b_mclk_mux.hw,
>> + [AUD_CLKID_MST_B_MCLK_DIV] = &aud_mst_b_mclk_div.hw,
>> + [AUD_CLKID_MST_B_MCLK] = &aud_mst_b_mclk.hw,
>> + [AUD_CLKID_MST_C_MCLK_SEL] = &aud_mst_c_mclk_mux.hw,
>> + [AUD_CLKID_MST_C_MCLK_DIV] = &aud_mst_c_mclk_div.hw,
>> + [AUD_CLKID_MST_C_MCLK] = &aud_mst_c_mclk.hw,
>> + [AUD_CLKID_MST_D_MCLK_SEL] = &aud_mst_d_mclk_mux.hw,
>> + [AUD_CLKID_MST_D_MCLK_DIV] = &aud_mst_d_mclk_div.hw,
>> + [AUD_CLKID_MST_D_MCLK] = &aud_mst_d_mclk.hw,
>> + [AUD_CLKID_RESAMPLE_CLK_SEL] = &aud_resample_clk_mux.hw,
>> + [AUD_CLKID_RESAMPLE_CLK_DIV] = &aud_resample_clk_div.hw,
>> + [AUD_CLKID_RESAMPLE_CLK] = &aud_resample_clk.hw,
>> + [AUD_CLKID_LOCKER_IN_CLK_SEL] = &aud_locker_in_clk_mux.hw,
>> + [AUD_CLKID_LOCKER_IN_CLK_DIV] = &aud_locker_in_clk_div.hw,
>> + [AUD_CLKID_LOCKER_IN_CLK] = &aud_locker_in_clk.hw,
>> + [AUD_CLKID_LOCKER_OUT_CLK_SEL] = &aud_locker_out_clk_mux.hw,
>> + [AUD_CLKID_LOCKER_OUT_CLK_DIV] = &aud_locker_out_clk_div.hw,
>> + [AUD_CLKID_LOCKER_OUT_CLK] = &aud_locker_out_clk.hw,
>> + [AUD_CLKID_SPDIFIN_CLK_SEL] = &aud_spdifin_clk_mux.hw,
>> + [AUD_CLKID_SPDIFIN_CLK_DIV] = &aud_spdifin_clk_div.hw,
>> + [AUD_CLKID_SPDIFIN_CLK] = &aud_spdifin_clk.hw,
>> + [AUD_CLKID_EQDRC_CLK_SEL] = &aud_eqdrc_clk_mux.hw,
>> + [AUD_CLKID_EQDRC_CLK_DIV] = &aud_eqdrc_clk_div.hw,
>> + [AUD_CLKID_EQDRC_CLK] = &aud_eqdrc_clk.hw,
>> + [AUD_CLKID_MST_A_SCLK_PRE_EN] = &aud_mst_a_sclk_pre_en.hw,
>> + [AUD_CLKID_MST_A_SCLK_DIV] = &aud_mst_a_sclk_div.hw,
>> + [AUD_CLKID_MST_A_SCLK_POST_EN] = &aud_mst_a_sclk_post_en.hw,
>> + [AUD_CLKID_MST_A_SCLK] = &aud_mst_a_sclk.hw,
>> + [AUD_CLKID_MST_B_SCLK_PRE_EN] = &aud_mst_b_sclk_pre_en.hw,
>> + [AUD_CLKID_MST_B_SCLK_DIV] = &aud_mst_b_sclk_div.hw,
>> + [AUD_CLKID_MST_B_SCLK_POST_EN] = &aud_mst_b_sclk_post_en.hw,
>> + [AUD_CLKID_MST_B_SCLK] = &aud_mst_b_sclk.hw,
>> + [AUD_CLKID_MST_C_SCLK_PRE_EN] = &aud_mst_c_sclk_pre_en.hw,
>> + [AUD_CLKID_MST_C_SCLK_DIV] = &aud_mst_c_sclk_div.hw,
>> + [AUD_CLKID_MST_C_SCLK_POST_EN] = &aud_mst_c_sclk_post_en.hw,
>> + [AUD_CLKID_MST_C_SCLK] = &aud_mst_c_sclk.hw,
>> + [AUD_CLKID_MST_D_SCLK_PRE_EN] = &aud_mst_d_sclk_pre_en.hw,
>> + [AUD_CLKID_MST_D_SCLK_DIV] = &aud_mst_d_sclk_div.hw,
>> + [AUD_CLKID_MST_D_SCLK_POST_EN] = &aud_mst_d_sclk_post_en.hw,
>> + [AUD_CLKID_MST_D_SCLK] = &aud_mst_d_sclk.hw,
>> + [AUD_CLKID_MST_A_LRCLK_DIV] = &aud_mst_a_lrclk_div.hw,
>> + [AUD_CLKID_MST_A_LRCLK] = &aud_mst_a_lrclk.hw,
>> + [AUD_CLKID_MST_B_LRCLK_DIV] = &aud_mst_b_lrclk_div.hw,
>> + [AUD_CLKID_MST_B_LRCLK] = &aud_mst_b_lrclk.hw,
>> + [AUD_CLKID_MST_C_LRCLK_DIV] = &aud_mst_c_lrclk_div.hw,
>> + [AUD_CLKID_MST_C_LRCLK] = &aud_mst_c_lrclk.hw,
>> + [AUD_CLKID_MST_D_LRCLK_DIV] = &aud_mst_d_lrclk_div.hw,
>> + [AUD_CLKID_MST_D_LRCLK] = &aud_mst_d_lrclk.hw,
>> + [AUD_CLKID_TDMIN_A_SCLK_SEL] = &aud_tdmin_a_sclk_mux.hw,
>> + [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &aud_tdmin_a_sclk_pre_en.hw,
>> + [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &aud_tdmin_a_sclk_post_en.hw,
>> + [AUD_CLKID_TDMIN_A_SCLK] = &aud_tdmin_a_sclk.hw,
>> + [AUD_CLKID_TDMIN_A_LRCLK] = &aud_tdmin_a_lrclk.hw,
>> + [AUD_CLKID_TDMIN_B_SCLK_SEL] = &aud_tdmin_b_sclk_mux.hw,
>> + [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &aud_tdmin_b_sclk_pre_en.hw,
>> + [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &aud_tdmin_b_sclk_post_en.hw,
>> + [AUD_CLKID_TDMIN_B_SCLK] = &aud_tdmin_b_sclk.hw,
>> + [AUD_CLKID_TDMIN_B_LRCLK] = &aud_tdmin_b_lrclk.hw,
>> + [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &aud_tdmin_lb_sclk_mux.hw,
>> + [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &aud_tdmin_lb_sclk_pre_en.hw,
>> + [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &aud_tdmin_lb_sclk_post_en.hw,
>> + [AUD_CLKID_TDMIN_LB_SCLK] = &aud_tdmin_lb_sclk.hw,
>> + [AUD_CLKID_TDMIN_LB_LRCLK] = &aud_tdmin_lb_lrclk.hw,
>> + [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &aud_tdmout_a_sclk_mux.hw,
>> + [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &aud_tdmout_a_sclk_pre_en.hw,
>> + [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &aud_tdmout_a_sclk_post_en.hw,
>> + [AUD_CLKID_TDMOUT_A_SCLK] = &aud_tdmout_a_sclk.hw,
>> + [AUD_CLKID_TDMOUT_A_LRCLK] = &aud_tdmout_a_lrclk.hw,
>> + [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &aud_tdmout_b_sclk_mux.hw,
>> + [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &aud_tdmout_b_sclk_pre_en.hw,
>> + [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &aud_tdmout_b_sclk_post_en.hw,
>> + [AUD_CLKID_TDMOUT_B_SCLK] = &aud_tdmout_b_sclk.hw,
>> + [AUD_CLKID_TDMOUT_B_LRCLK] = &aud_tdmout_b_lrclk.hw,
>> +};
>> +
>> +static struct clk_hw *a1_audio2_hw_clks[] = {
>> + [AUD2_CLKID_DDR_ARB] = &aud2_ddr_arb.hw,
>> + [AUD2_CLKID_PDM] = &aud2_pdm.hw,
>> + [AUD2_CLKID_TDMIN_VAD] = &aud2_tdmin_vad.hw,
>> + [AUD2_CLKID_TODDR_VAD] = &aud2_toddr_vad.hw,
>> + [AUD2_CLKID_VAD] = &aud2_vad.hw,
>> + [AUD2_CLKID_AUDIOTOP] = &aud2_audiotop.hw,
>> + [AUD2_CLKID_VAD_MCLK_SEL] = &aud2_vad_mclk_mux.hw,
>> + [AUD2_CLKID_VAD_MCLK_DIV] = &aud2_vad_mclk_div.hw,
>> + [AUD2_CLKID_VAD_MCLK] = &aud2_vad_mclk.hw,
>> + [AUD2_CLKID_VAD_CLK_SEL] = &aud2_vad_clk_mux.hw,
>> + [AUD2_CLKID_VAD_CLK_DIV] = &aud2_vad_clk_div.hw,
>> + [AUD2_CLKID_VAD_CLK] = &aud2_vad_clk.hw,
>> + [AUD2_CLKID_PDM_DCLK_SEL] = &aud2_pdm_dclk_mux.hw,
>> + [AUD2_CLKID_PDM_DCLK_DIV] = &aud2_pdm_dclk_div.hw,
>> + [AUD2_CLKID_PDM_DCLK] = &aud2_pdm_dclk.hw,
>> + [AUD2_CLKID_PDM_SYSCLK_SEL] = &aud2_pdm_sysclk_mux.hw,
>> + [AUD2_CLKID_PDM_SYSCLK_DIV] = &aud2_pdm_sysclk_div.hw,
>> + [AUD2_CLKID_PDM_SYSCLK] = &aud2_pdm_sysclk.hw,
>> +};
>
> I think you already got that comment but audio2 is a terrible name.
>> Given that the 2nd controller is mostly about VAD (PDM is there only to
> feed it) and that it is just a name, I'd prefer something like a1_audio_vad.
>
Do you mean something like this?
static struct clk_hw *a1_audio_vad_hw_clks[] = {
[AUD_CLKID_VAD_DDR_ARB] = &aud_vad_ddr_arb.hw,
[AUD_CLKID_VAD_PDM] = &aud_vad_pdm.hw,
[AUD_CLKID_VAD_TDMIN] = &aud_vad_tdmin.hw,
[AUD_CLKID_VAD_TODDR] = &aud_vad_toddr.hw,
[AUD_CLKID_VAD] = &aud_vad.hw,
...
>> +
>> +static int a1_register_clk(struct platform_device *pdev, struct regmap *map,
>> + struct clk_hw *hw)
>> +{
>> + struct clk_regmap *clk = container_of(hw, struct clk_regmap, hw);
>> +
>> + if (!hw)
>> + return 0;
>> +
>> + clk->map = map;
>> +
>> + return devm_clk_hw_register(&pdev->dev, hw);
>> +}
>
> Why do you have to do that and cannot do it like the rest of the
> modules ?
>
Originally, it was used twice. But you're right, now it can be placed
into the loop in a1_audio_clkc_probe().
>> +
>> +struct a1_audio_data {
>> + struct meson_clk_hw_data hw_clks;
>> + int core_clkid;
>> + const char *core_fwname;
>> + unsigned int reset_offset;
>> + unsigned int reset_num;
>> +};
>> +
>> +static const struct regmap_config a1_audio_regmap_cfg = {
>> + .reg_bits = 32,
>> + .val_bits = 32,
>> + .reg_stride = 4,
>> +};
>> +
>> +static int a1_audio_clkc_probe(struct platform_device *pdev)
>> +{
>> + const struct a1_audio_data *data;
>> + struct regmap *map;
>> + void __iomem *base;
>> + struct clk *clk;
>> + unsigned int i;
>> + int ret;
>> +
>> + data = of_device_get_match_data(&pdev->dev);
>> + if (!data)
>> + return -EINVAL;
>> +
>> + if (data->core_fwname) {
>
> That is really over-complicated for what it does ....
>
>> + clk = devm_clk_get_enabled(&pdev->dev, data->core_fwname);
>
> It does not make a lot of sense that one of the 2 controllers as 2nd
> pclk.
> > You should consider using the AUD2_CLKID_AUDIOTOP as a parent of audio
> gates instead. You would not have to that.
>
>> + if (IS_ERR(clk))
>> + return PTR_ERR(clk);
>> + }
>
>
>
>> +
>> + base = devm_platform_ioremap_resource(pdev, 0);
>> + if (IS_ERR(base))
>> + return PTR_ERR(base);
>> +
>> + map = devm_regmap_init_mmio(&pdev->dev, base, &a1_audio_regmap_cfg);
>> + if (IS_ERR(map))
>> + return PTR_ERR(map);
>> +
>> + clk = devm_clk_get_enabled(&pdev->dev, "pclk");
>> + if (IS_ERR(clk))
>> + return PTR_ERR(clk);
>> +
>> + for (i = 0; i < data->hw_clks.num; i++) {
>> + struct clk_hw *hw = data->hw_clks.hws[i];
>> +
>> + ret = a1_register_clk(pdev, map, hw);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + ret = devm_of_clk_add_hw_provider(&pdev->dev, meson_clk_hw_get,
>> + (void *)&data->hw_clks);
>> + if (ret)
>> + return ret;
>> +
>> + if (!data->reset_num)
>> + return 0;
>> +
>> + return meson_audio_rstc_register(&pdev->dev, map, data->reset_offset,
>> + data->reset_num);
>> +}>
> Again this is over-complicated.> Just make an external function for the register, use it for axg, a1,
> a1-vad, then make one file for each controller. That will keep the code
> clean and readable.
>
It's a bit unclear here. Is this a general recommendation or is it
specific to _this_ location in the code?
> Just make an external function for the register
Dou you suggest to share something like a1_register_clk()? Currently, it
is not good idea, axg-audio uses slightly different way to register
their clocks.
> keep it simple please.
>
>> +
>> +struct a1_audio_data a1_audio_data = {
>> + .hw_clks = {
>> + .hws = a1_audio_hw_clks,
>> + .num = ARRAY_SIZE(a1_audio_hw_clks),
>> + },
>> + .core_fwname = "core",
>> + .reset_offset = AUDIO_SW_RESET0,
>> + .reset_num = 32,
>> +};
>> +
>> +struct a1_audio_data a1_audio2_data = {
>> + .hw_clks = {
>> + .hws = a1_audio2_hw_clks,
>> + .num = ARRAY_SIZE(a1_audio2_hw_clks),
>> + },
>> +};
>> +
>> +static const struct of_device_id a1_audio_clkc_match_table[] = {
>> + {
>> + .compatible = "amlogic,a1-audio-clkc",
>> + .data = &a1_audio_data,
>> + },
>> + {
>> + .compatible = "amlogic,a1-audio2-clkc",
>> + .data = &a1_audio2_data,
>> + },
>> + {}
>> +};
>> +MODULE_DEVICE_TABLE(of, a1_audio_clkc_match_table);
>> +
>> +static struct platform_driver a1_audio_clkc_driver = {
>> + .probe = a1_audio_clkc_probe,
>> + .driver = {
>> + .name = "a1-audio-clkc",
>> + .of_match_table = a1_audio_clkc_match_table,
>> + },
>> +};
>> +module_platform_driver(a1_audio_clkc_driver);
>> +
>> +MODULE_DESCRIPTION("Amlogic A1 Audio Clock driver");
>> +MODULE_AUTHOR("Jan Dakinevich <jan.dakinevich@salutedevices.com>");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/clk/meson/a1-audio.h b/drivers/clk/meson/a1-audio.h
>> new file mode 100644
>> index 000000000000..9ea9da21ff9b
>> --- /dev/null
>> +++ b/drivers/clk/meson/a1-audio.h
>> @@ -0,0 +1,45 @@
>> +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
>> +/*
>> + * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
>> + *
>> + * Author: Jan Dakinevich <jan.dakinevich@salutedevices.com>
>> + */
>> +
>> +#ifndef __A1_AUDIO_H
>> +#define __A1_AUDIO_H
>> +
>> +#define AUDIO_CLK_GATE_EN0 0x000
>> +#define AUDIO_MCLK_A_CTRL 0x008
>> +#define AUDIO_MCLK_B_CTRL 0x00c
>> +#define AUDIO_MCLK_C_CTRL 0x010
>> +#define AUDIO_MCLK_D_CTRL 0x014
>> +#define AUDIO_MCLK_E_CTRL 0x018
>> +#define AUDIO_MCLK_F_CTRL 0x01c
>> +#define AUDIO_SW_RESET0 0x028
>> +#define AUDIO_MST_A_SCLK_CTRL0 0x040
>> +#define AUDIO_MST_A_SCLK_CTRL1 0x044
>> +#define AUDIO_MST_B_SCLK_CTRL0 0x048
>> +#define AUDIO_MST_B_SCLK_CTRL1 0x04c
>> +#define AUDIO_MST_C_SCLK_CTRL0 0x050
>> +#define AUDIO_MST_C_SCLK_CTRL1 0x054
>> +#define AUDIO_MST_D_SCLK_CTRL0 0x058
>> +#define AUDIO_MST_D_SCLK_CTRL1 0x05c
>> +#define AUDIO_CLK_TDMIN_A_CTRL 0x080
>> +#define AUDIO_CLK_TDMIN_B_CTRL 0x084
>> +#define AUDIO_CLK_TDMIN_LB_CTRL 0x08c
>> +#define AUDIO_CLK_TDMOUT_A_CTRL 0x090
>> +#define AUDIO_CLK_TDMOUT_B_CTRL 0x094
>> +#define AUDIO_CLK_SPDIFIN_CTRL 0x09c
>> +#define AUDIO_CLK_RESAMPLE_CTRL 0x0a4
>> +#define AUDIO_CLK_LOCKER_CTRL 0x0a8
>> +#define AUDIO_CLK_EQDRC_CTRL 0x0c0
>> +
>> +#define AUDIO2_CLK_GATE_EN0 0x00c
>> +#define AUDIO2_MCLK_VAD_CTRL 0x040
>> +#define AUDIO2_CLK_VAD_CTRL 0x044
>> +#define AUDIO2_CLK_PDMIN_CTRL0 0x058
>> +#define AUDIO2_CLK_PDMIN_CTRL1 0x05c
>
> Same remark - header is useless.
>
Do you suggest to move these defines to source file and kill this header?
>> +
>> +#include <dt-bindings/clock/amlogic,a1-audio-clkc.h>
>> +
>> +#endif /* __A1_AUDIO_H */
>
>
--
Best regards
Jan Dakinevich
^ permalink raw reply
* Re: [PATCH v9 1/7] dt-bindings: spmi: Add X1E80100 SPMI PMIC ARB schema
From: Bjorn Andersson @ 2024-04-08 0:07 UTC (permalink / raw)
To: Abel Vesa
Cc: Stephen Boyd, Matthias Brugger, Konrad Dybcio, Dmitry Baryshkov,
Neil Armstrong, AngeloGioacchino Del Regno, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Srini Kandagatla, Johan Hovold,
David Collins, linux-kernel, linux-arm-kernel, linux-arm-msm,
linux-mediatek, devicetree, Krzysztof Kozlowski
In-Reply-To: <20240407-spmi-multi-master-support-v9-1-fa151c1391f3@linaro.org>
On Sun, Apr 07, 2024 at 07:23:21PM +0300, Abel Vesa wrote:
> Add dedicated schema for X1E80100 PMIC ARB (v7) as it allows multiple
> buses by declaring them as child nodes.
>
But is this really a "dedicated schema for X1E80100"? Isn't it "the
schema for all multi-bus controllers"?
I.e. isn't this a "dedicated schema for all platforms starting with
SM8450"?
Can you please use the commit message to document the actual reason why
you choose to create a dedicated schema for this? Is it simply to avoid
having to schema with either pmics or multiple buses as children?
Regards,
Bjorn
^ permalink raw reply
* [PATCH v4 4/4] arm64: dts: qcom: msm8996: drop source clock entries from the UFS node
From: Dmitry Baryshkov @ 2024-04-08 0:04 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio,
James E.J. Bottomley, Martin K. Petersen, Nitin Rawat, Can Guo,
Naveen Kumar Goud Arepalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Alim Akhtar, Avri Altman, Bart Van Assche,
Andy Gross
Cc: linux-arm-msm, linux-scsi, devicetree
In-Reply-To: <20240408-msm8996-fix-ufs-v4-0-ee1a28bf8579@linaro.org>
There is no need to mention and/or to touch in any way the intermediate
(source) clocks. Drop them from MSM8996 UFSHCD schema, making it follow
the example lead by all other platforms.
Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
arch/arm64/boot/dts/qcom/msm8996.dtsi | 6 ------
1 file changed, 6 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index da7f599bd2a5..708f797f1b44 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -2047,24 +2047,20 @@ ufshc: ufshc@624000 {
power-domains = <&gcc UFS_GDSC>;
clock-names =
- "core_clk_src",
"core_clk",
"bus_clk",
"bus_aggr_clk",
"iface_clk",
- "core_clk_unipro_src",
"core_clk_unipro",
"core_clk_ice",
"ref_clk",
"tx_lane0_sync_clk",
"rx_lane0_sync_clk";
clocks =
- <&gcc UFS_AXI_CLK_SRC>,
<&gcc GCC_UFS_AXI_CLK>,
<&gcc GCC_SYS_NOC_UFS_AXI_CLK>,
<&gcc GCC_AGGRE2_UFS_AXI_CLK>,
<&gcc GCC_UFS_AHB_CLK>,
- <&gcc UFS_ICE_CORE_CLK_SRC>,
<&gcc GCC_UFS_UNIPRO_CORE_CLK>,
<&gcc GCC_UFS_ICE_CORE_CLK>,
<&rpmcc RPM_SMD_LN_BB_CLK>,
@@ -2072,8 +2068,6 @@ ufshc: ufshc@624000 {
<&gcc GCC_UFS_RX_SYMBOL_0_CLK>;
freq-table-hz =
<100000000 200000000>,
- <100000000 200000000>,
- <0 0>,
<0 0>,
<0 0>,
<0 0>,
--
2.39.2
^ permalink raw reply related
* [PATCH v4 3/4] dt-bindings: ufs: qcom,ufs: drop source clock entries
From: Dmitry Baryshkov @ 2024-04-08 0:04 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio,
James E.J. Bottomley, Martin K. Petersen, Nitin Rawat, Can Guo,
Naveen Kumar Goud Arepalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Alim Akhtar, Avri Altman, Bart Van Assche,
Andy Gross
Cc: linux-arm-msm, linux-scsi, devicetree, Krzysztof Kozlowski
In-Reply-To: <20240408-msm8996-fix-ufs-v4-0-ee1a28bf8579@linaro.org>
There is no need to mention and/or to touch in any way the intermediate
(source) clocks. Drop them from MSM8996 UFSHCD schema, making it follow
the example lead by all other platforms.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Acked-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
Documentation/devicetree/bindings/ufs/qcom,ufs.yaml | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml
index cd3680dc002f..25a5edeea164 100644
--- a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml
+++ b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml
@@ -46,11 +46,11 @@ properties:
clocks:
minItems: 7
- maxItems: 11
+ maxItems: 9
clock-names:
minItems: 7
- maxItems: 11
+ maxItems: 9
dma-coherent: true
@@ -217,16 +217,14 @@ allOf:
then:
properties:
clocks:
- minItems: 11
- maxItems: 11
+ minItems: 9
+ maxItems: 9
clock-names:
items:
- - const: core_clk_src
- const: core_clk
- const: bus_clk
- const: bus_aggr_clk
- const: iface_clk
- - const: core_clk_unipro_src
- const: core_clk_unipro
- const: core_clk_ice
- const: ref_clk
@@ -287,7 +285,7 @@ allOf:
maxItems: 2
clocks:
minItems: 7
- maxItems: 11
+ maxItems: 9
unevaluatedProperties: false
--
2.39.2
^ permalink raw reply related
* [PATCH v4 2/4] arm64: dts: qcom: msm8996: set GCC_UFS_ICE_CORE_CLK freq directly
From: Dmitry Baryshkov @ 2024-04-08 0:04 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio,
James E.J. Bottomley, Martin K. Petersen, Nitin Rawat, Can Guo,
Naveen Kumar Goud Arepalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Alim Akhtar, Avri Altman, Bart Van Assche,
Andy Gross
Cc: linux-arm-msm, linux-scsi, devicetree
In-Reply-To: <20240408-msm8996-fix-ufs-v4-0-ee1a28bf8579@linaro.org>
Instead of setting the frequency of the interim UFS_ICE_CORE_CLK_SRC
clock, set the frequency of the leaf GCC_UFS_ICE_CORE_CLK clock directly.
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
arch/arm64/boot/dts/qcom/msm8996.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index 42ad4872f94d..da7f599bd2a5 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -2076,9 +2076,9 @@ ufshc: ufshc@624000 {
<0 0>,
<0 0>,
<0 0>,
- <150000000 300000000>,
- <75000000 150000000>,
<0 0>,
+ <75000000 150000000>,
+ <150000000 300000000>,
<0 0>,
<0 0>,
<0 0>;
--
2.39.2
^ permalink raw reply related
* [PATCH v4 1/4] arm64: dts: qcom: msm8996: specify UFS core_clk frequencies
From: Dmitry Baryshkov @ 2024-04-08 0:04 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio,
James E.J. Bottomley, Martin K. Petersen, Nitin Rawat, Can Guo,
Naveen Kumar Goud Arepalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Alim Akhtar, Avri Altman, Bart Van Assche,
Andy Gross
Cc: linux-arm-msm, linux-scsi, devicetree
In-Reply-To: <20240408-msm8996-fix-ufs-v4-0-ee1a28bf8579@linaro.org>
Follow the example of other platforms and specify core_clk frequencies
in the frequency table in addition to the core_clk_src frequencies. The
driver should be setting the leaf frequency instead of some interim
clock freq.
Suggested-by: Nitin Rawat <quic_nitirawa@quicinc.com>
Fixes: 57fc67ef0d35 ("arm64: dts: qcom: msm8996: Add ufs related nodes")
Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
arch/arm64/boot/dts/qcom/msm8996.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index 1601e46549e7..42ad4872f94d 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -2072,7 +2072,7 @@ ufshc: ufshc@624000 {
<&gcc GCC_UFS_RX_SYMBOL_0_CLK>;
freq-table-hz =
<100000000 200000000>,
- <0 0>,
+ <100000000 200000000>,
<0 0>,
<0 0>,
<0 0>,
--
2.39.2
^ permalink raw reply related
* [PATCH v4 0/4] scsi: ufs: qcom: fix UFSDHCD support on MSM8996 platform
From: Dmitry Baryshkov @ 2024-04-08 0:04 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bjorn Andersson, Konrad Dybcio,
James E.J. Bottomley, Martin K. Petersen, Nitin Rawat, Can Guo,
Naveen Kumar Goud Arepalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Alim Akhtar, Avri Altman, Bart Van Assche,
Andy Gross
Cc: linux-arm-msm, linux-scsi, devicetree, Krzysztof Kozlowski
First several patches target fixing the UFS support on the Qualcomm
MSM8996 / APQ8096 platforms, broken by the commit b4e13e1ae95e ("scsi:
ufs: qcom: Add multiple frequency support for MAX_CORE_CLK_1US_CYCLES").
Last two patches clean up the UFS DT device on that platform to follow
the bindings on other MSM8969 platforms. If such breaking change is
unacceptable, they can be simply ignored, merging fixes only.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
Changes in v4:
- Rebased on top of linux-next to resolve conflict with UFS schema
changes
- Link to v3: https://lore.kernel.org/r/20240218-msm8996-fix-ufs-v3-0-40aab49899a3@linaro.org
Changes in v3:
- dropped the patch conflicting with Yassine's patch that got accepted
- Cc stable on the UFS change (Manivannan)
- Fixed typos in the commit message (Manivannan)
- Link to v2: https://lore.kernel.org/r/20240213-msm8996-fix-ufs-v2-0-650758c26458@linaro.org
Changes in v2:
- Dropped patches adding RX_SYMBOL_1_CLK, MSM8996 uses single lane
(Krzysztof).
- Link to v1: https://lore.kernel.org/r/20240209-msm8996-fix-ufs-v1-0-107b52e57420@linaro.org
---
Dmitry Baryshkov (4):
arm64: dts: qcom: msm8996: specify UFS core_clk frequencies
arm64: dts: qcom: msm8996: set GCC_UFS_ICE_CORE_CLK freq directly
dt-bindings: ufs: qcom,ufs: drop source clock entries
arm64: dts: qcom: msm8996: drop source clock entries from the UFS node
Documentation/devicetree/bindings/ufs/qcom,ufs.yaml | 12 +++++-------
arch/arm64/boot/dts/qcom/msm8996.dtsi | 8 +-------
2 files changed, 6 insertions(+), 14 deletions(-)
---
base-commit: 8568bb2ccc278f344e6ac44af6ed010a90aa88dc
change-id: 20240209-msm8996-fix-ufs-f80ae6d4d8cf
Best regards,
--
Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
^ permalink raw reply
* [PATCH v5 4/4] drm: panel: Add LG sw43408 panel driver
From: Dmitry Baryshkov @ 2024-04-07 23:53 UTC (permalink / raw)
To: Sumit Semwal, Caleb Connolly, Neil Armstrong, Jessica Zhang,
Sam Ravnborg, David Airlie, Daniel Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: dri-devel, devicetree, linux-kernel, linux-arm-msm, Vinod Koul,
Caleb Connolly, Marijn Suijten
In-Reply-To: <20240408-lg-sw43408-panel-v5-0-4e092da22991@linaro.org>
From: Sumit Semwal <sumit.semwal@linaro.org>
LG SW43408 is 1080x2160@60Hz, 4-lane MIPI-DSI panel, used in some
Google Pixel-3 phones.
Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
[vinod: Add DSC support]
Signed-off-by: Vinod Koul <vkoul@kernel.org>
[caleb: cleanup and support turning off the panel]
Signed-off-by: Caleb Connolly <caleb@connolly.tech>
[DB: partially rewrote the driver and fixed DSC programming]
Reviewed-by: Marijn Suijten <marijn.suijten@somainline.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
MAINTAINERS | 8 +
drivers/gpu/drm/panel/Kconfig | 11 ++
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-lg-sw43408.c | 323 +++++++++++++++++++++++++++++++
4 files changed, 343 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index d36c19c1bf81..4cc43c16e07e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6789,6 +6789,14 @@ S: Maintained
F: Documentation/devicetree/bindings/display/panel/jadard,jd9365da-h3.yaml
F: drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
+DRM DRIVER FOR LG SW43408 PANELS
+M: Sumit Semwal <sumit.semwal@linaro.org>
+M: Caleb Connolly <caleb.connolly@linaro.org>
+S: Maintained
+T: git git://anongit.freedesktop.org/drm/drm-misc
+F: Documentation/devicetree/bindings/display/panel/lg,sw43408.yaml
+F: drivers/gpu/drm/panel/panel-lg-sw43408.c
+
DRM DRIVER FOR LOGICVC DISPLAY CONTROLLER
M: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
S: Supported
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 6dc451f58a3e..4dc435fd9a44 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -335,6 +335,17 @@ config DRM_PANEL_LG_LG4573
Say Y here if you want to enable support for LG4573 RGB panel.
To compile this driver as a module, choose M here.
+config DRM_PANEL_LG_SW43408
+ tristate "LG SW43408 panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y here if you want to enable support for LG sw43408 panel.
+ The panel has a 1080x2160@60Hz resolution and uses 24 bit RGB per
+ pixel. It provides a MIPI DSI interface to the host and has a
+ built-in LED backlight.
+
config DRM_PANEL_MAGNACHIP_D53E6EA8966
tristate "Magnachip D53E6EA8966 DSI panel"
depends on OF && SPI
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 24a02655d726..0b40b010e8e7 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
+obj-$(CONFIG_DRM_PANEL_LG_SW43408) += panel-lg-sw43408.o
obj-$(CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966) += panel-magnachip-d53e6ea8966.o
obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3051D) += panel-newvision-nv3051d.o
diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c
new file mode 100644
index 000000000000..bd9706ae7615
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-2024 Linaro Ltd
+ * Author: Sumit Semwal <sumit.semwal@linaro.org>
+ * Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/display/drm_dsc.h>
+#include <drm/display/drm_dsc_helper.h>
+
+#define NUM_SUPPLIES 2
+
+struct sw43408_panel {
+ struct drm_panel base;
+ struct mipi_dsi_device *link;
+
+ struct regulator_bulk_data supplies[NUM_SUPPLIES];
+
+ struct gpio_desc *reset_gpio;
+
+ struct drm_dsc_config dsc;
+};
+
+static inline struct sw43408_panel *to_panel_info(struct drm_panel *panel)
+{
+ return container_of(panel, struct sw43408_panel, base);
+}
+
+static int sw43408_unprepare(struct drm_panel *panel)
+{
+ struct sw43408_panel *ctx = to_panel_info(panel);
+ int ret;
+
+ ret = mipi_dsi_dcs_set_display_off(ctx->link);
+ if (ret < 0)
+ dev_err(panel->dev, "set_display_off cmd failed ret = %d\n", ret);
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(ctx->link);
+ if (ret < 0)
+ dev_err(panel->dev, "enter_sleep cmd failed ret = %d\n", ret);
+
+ msleep(100);
+
+ gpiod_set_value(ctx->reset_gpio, 1);
+
+ return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+}
+
+static int sw43408_program(struct drm_panel *panel)
+{
+ struct sw43408_panel *ctx = to_panel_info(panel);
+ struct drm_dsc_picture_parameter_set pps;
+
+ mipi_dsi_dcs_write_seq(ctx->link, MIPI_DCS_SET_GAMMA_CURVE, 0x02);
+
+ mipi_dsi_dcs_set_tear_on(ctx->link, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+
+ mipi_dsi_dcs_write_seq(ctx->link, 0x53, 0x0c, 0x30);
+ mipi_dsi_dcs_write_seq(ctx->link, 0x55, 0x00, 0x70, 0xdf, 0x00, 0x70, 0xdf);
+ mipi_dsi_dcs_write_seq(ctx->link, 0xf7, 0x01, 0x49, 0x0c);
+
+ mipi_dsi_dcs_exit_sleep_mode(ctx->link);
+
+ msleep(135);
+
+ /* COMPRESSION_MODE moved after setting the PPS */
+
+ mipi_dsi_dcs_write_seq(ctx->link, 0xb0, 0xac);
+ mipi_dsi_dcs_write_seq(ctx->link, 0xe5,
+ 0x00, 0x3a, 0x00, 0x3a, 0x00, 0x0e, 0x10);
+ mipi_dsi_dcs_write_seq(ctx->link, 0xb5,
+ 0x75, 0x60, 0x2d, 0x5d, 0x80, 0x00, 0x0a, 0x0b,
+ 0x00, 0x05, 0x0b, 0x00, 0x80, 0x0d, 0x0e, 0x40,
+ 0x00, 0x0c, 0x00, 0x16, 0x00, 0xb8, 0x00, 0x80,
+ 0x0d, 0x0e, 0x40, 0x00, 0x0c, 0x00, 0x16, 0x00,
+ 0xb8, 0x00, 0x81, 0x00, 0x03, 0x03, 0x03, 0x01,
+ 0x01);
+ msleep(85);
+ mipi_dsi_dcs_write_seq(ctx->link, 0xcd,
+ 0x00, 0x00, 0x00, 0x19, 0x19, 0x19, 0x19, 0x19,
+ 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+ 0x16, 0x16);
+ mipi_dsi_dcs_write_seq(ctx->link, 0xcb, 0x80, 0x5c, 0x07, 0x03, 0x28);
+ mipi_dsi_dcs_write_seq(ctx->link, 0xc0, 0x02, 0x02, 0x0f);
+ mipi_dsi_dcs_write_seq(ctx->link, 0x55, 0x04, 0x61, 0xdb, 0x04, 0x70, 0xdb);
+ mipi_dsi_dcs_write_seq(ctx->link, 0xb0, 0xca);
+
+ mipi_dsi_dcs_set_display_on(ctx->link);
+
+ msleep(50);
+
+ ctx->link->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ drm_dsc_pps_payload_pack(&pps, ctx->link->dsc);
+ mipi_dsi_picture_parameter_set(ctx->link, &pps);
+
+ ctx->link->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ /*
+ * This panel uses PPS selectors with offset:
+ * PPS 1 if pps_identifier is 0
+ * PPS 2 if pps_identifier is 1
+ */
+ mipi_dsi_compression_mode_ext(ctx->link, true,
+ MIPI_DSI_COMPRESSION_DSC, 1);
+
+
+ return 0;
+}
+
+static int sw43408_prepare(struct drm_panel *panel)
+{
+ struct sw43408_panel *ctx = to_panel_info(panel);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(5000, 6000);
+
+ gpiod_set_value(ctx->reset_gpio, 0);
+ usleep_range(9000, 10000);
+ gpiod_set_value(ctx->reset_gpio, 1);
+ usleep_range(1000, 2000);
+ gpiod_set_value(ctx->reset_gpio, 0);
+ usleep_range(9000, 10000);
+
+ ret = sw43408_program(panel);
+ if (ret)
+ goto poweroff;
+
+ return 0;
+
+poweroff:
+ gpiod_set_value(ctx->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+ return ret;
+}
+
+static const struct drm_display_mode sw43408_mode = {
+ .clock = (1080 + 20 + 32 + 20) * (2160 + 20 + 4 + 20) * 60 / 1000,
+
+ .hdisplay = 1080,
+ .hsync_start = 1080 + 20,
+ .hsync_end = 1080 + 20 + 32,
+ .htotal = 1080 + 20 + 32 + 20,
+
+ .vdisplay = 2160,
+ .vsync_start = 2160 + 20,
+ .vsync_end = 2160 + 20 + 4,
+ .vtotal = 2160 + 20 + 4 + 20,
+
+ .width_mm = 62,
+ .height_mm = 124,
+
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static int sw43408_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ return drm_connector_helper_get_modes_fixed(connector, &sw43408_mode);
+}
+
+static int sw43408_backlight_update_status(struct backlight_device *bl)
+{
+ struct mipi_dsi_device *dsi = bl_get_data(bl);
+ uint16_t brightness = backlight_get_brightness(bl);
+
+ return mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
+}
+
+const struct backlight_ops sw43408_backlight_ops = {
+ .update_status = sw43408_backlight_update_status,
+};
+
+static int sw43408_backlight_init(struct sw43408_panel *ctx)
+{
+ struct device *dev = &ctx->link->dev;
+ const struct backlight_properties props = {
+ .type = BACKLIGHT_PLATFORM,
+ .brightness = 255,
+ .max_brightness = 255,
+ };
+
+ ctx->base.backlight = devm_backlight_device_register(dev, dev_name(dev), dev,
+ ctx->link,
+ &sw43408_backlight_ops,
+ &props);
+
+ if (IS_ERR(ctx->base.backlight))
+ return dev_err_probe(dev, PTR_ERR(ctx->base.backlight),
+ "Failed to create backlight\n");
+
+ return 0;
+}
+
+static const struct drm_panel_funcs sw43408_funcs = {
+ .unprepare = sw43408_unprepare,
+ .prepare = sw43408_prepare,
+ .get_modes = sw43408_get_modes,
+};
+
+static const struct of_device_id sw43408_of_match[] = {
+ { .compatible = "lg,sw43408", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sw43408_of_match);
+
+static int sw43408_add(struct sw43408_panel *ctx)
+{
+ struct device *dev = &ctx->link->dev;
+ int ret;
+
+ ctx->supplies[0].supply = "vddi"; /* 1.88 V */
+ ctx->supplies[0].init_load_uA = 62000;
+ ctx->supplies[1].supply = "vpnl"; /* 3.0 V */
+ ctx->supplies[1].init_load_uA = 857000;
+
+ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
+ ctx->supplies);
+ if (ret < 0)
+ return ret;
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset_gpio)) {
+ dev_err(dev, "cannot get reset gpio %ld\n",
+ PTR_ERR(ctx->reset_gpio));
+ return PTR_ERR(ctx->reset_gpio);
+ }
+
+ ret = sw43408_backlight_init(ctx);
+ if (ret < 0)
+ return ret;
+
+ ctx->base.prepare_prev_first = true;
+
+ drm_panel_init(&ctx->base, dev, &sw43408_funcs, DRM_MODE_CONNECTOR_DSI);
+
+ drm_panel_add(&ctx->base);
+ return ret;
+}
+
+static int sw43408_probe(struct mipi_dsi_device *dsi)
+{
+ struct sw43408_panel *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ dsi->mode_flags = MIPI_DSI_MODE_LPM;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->lanes = 4;
+
+ ctx->link = dsi;
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ ret = sw43408_add(ctx);
+ if (ret < 0)
+ return ret;
+
+ /* The panel works only in the DSC mode. Set DSC params. */
+ ctx->dsc.dsc_version_major = 0x1;
+ ctx->dsc.dsc_version_minor = 0x1;
+
+ /* slice_count * slice_width == width */
+ ctx->dsc.slice_height = 16;
+ ctx->dsc.slice_width = 540;
+ ctx->dsc.slice_count = 2;
+ ctx->dsc.bits_per_component = 8;
+ ctx->dsc.bits_per_pixel = 8 << 4;
+ ctx->dsc.block_pred_enable = true;
+
+ dsi->dsc = &ctx->dsc;
+
+ return mipi_dsi_attach(dsi);
+}
+
+static void sw43408_remove(struct mipi_dsi_device *dsi)
+{
+ struct sw43408_panel *ctx = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ ret = sw43408_unprepare(&ctx->base);
+ if (ret < 0)
+ dev_err(&dsi->dev, "failed to unprepare panel: %d\n",
+ ret);
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_remove(&ctx->base);
+}
+
+static struct mipi_dsi_driver sw43408_driver = {
+ .driver = {
+ .name = "panel-lg-sw43408",
+ .of_match_table = sw43408_of_match,
+ },
+ .probe = sw43408_probe,
+ .remove = sw43408_remove,
+};
+module_mipi_dsi_driver(sw43408_driver);
+
+MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>");
+MODULE_DESCRIPTION("LG SW436408 MIPI-DSI LED panel");
+MODULE_LICENSE("GPL");
--
2.39.2
^ permalink raw reply related
* [PATCH v5 3/4] drm/mipi-dsi: add mipi_dsi_compression_mode_ext()
From: Dmitry Baryshkov @ 2024-04-07 23:53 UTC (permalink / raw)
To: Sumit Semwal, Caleb Connolly, Neil Armstrong, Jessica Zhang,
Sam Ravnborg, David Airlie, Daniel Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: dri-devel, devicetree, linux-kernel, linux-arm-msm
In-Reply-To: <20240408-lg-sw43408-panel-v5-0-4e092da22991@linaro.org>
Add the extended version of mipi_dsi_compression_mode(). It provides
a way to specify the algorithm and PPS selector.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/drm_mipi_dsi.c | 41 ++++++++++++++++++++++++++++++++++-------
include/drm/drm_mipi_dsi.h | 9 +++++++++
2 files changed, 43 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index 9874ff6d4718..795001bb7ff1 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -645,29 +645,56 @@ int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size);
/**
- * mipi_dsi_compression_mode() - enable/disable DSC on the peripheral
+ * mipi_dsi_compression_mode_ext() - enable/disable DSC on the peripheral
* @dsi: DSI peripheral device
* @enable: Whether to enable or disable the DSC
+ * @algo: Selected compression algorithm
+ * @pps_selector: Select PPS from the table of pre-stored or uploaded PPS entries
*
- * Enable or disable Display Stream Compression on the peripheral using the
- * default Picture Parameter Set and VESA DSC 1.1 algorithm.
+ * Enable or disable Display Stream Compression on the peripheral.
*
* Return: 0 on success or a negative error code on failure.
*/
-int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable)
+int mipi_dsi_compression_mode_ext(struct mipi_dsi_device *dsi, bool enable,
+ enum mipi_dsi_compression_algo algo,
+ unsigned int pps_selector)
{
- /* Note: Needs updating for non-default PPS or algorithm */
- u8 tx[2] = { enable << 0, 0 };
+ u8 tx[2] = { };
struct mipi_dsi_msg msg = {
.channel = dsi->channel,
.type = MIPI_DSI_COMPRESSION_MODE,
.tx_len = sizeof(tx),
.tx_buf = tx,
};
- int ret = mipi_dsi_device_transfer(dsi, &msg);
+ int ret;
+
+ if (algo > 3 || pps_selector > 3)
+ return -EINVAL;
+
+ tx[0] = (enable << 0) |
+ (algo << 1) |
+ (pps_selector << 4);
+
+ ret = mipi_dsi_device_transfer(dsi, &msg);
return (ret < 0) ? ret : 0;
}
+EXPORT_SYMBOL(mipi_dsi_compression_mode_ext);
+
+/**
+ * mipi_dsi_compression_mode() - enable/disable DSC on the peripheral
+ * @dsi: DSI peripheral device
+ * @enable: Whether to enable or disable the DSC
+ *
+ * Enable or disable Display Stream Compression on the peripheral using the
+ * default Picture Parameter Set and VESA DSC 1.1 algorithm.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable)
+{
+ return mipi_dsi_compression_mode_ext(dsi, enable, MIPI_DSI_COMPRESSION_DSC, 0);
+}
EXPORT_SYMBOL(mipi_dsi_compression_mode);
/**
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 3011d33eccbd..82b1cc434ea3 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -226,6 +226,12 @@ static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
return -EINVAL;
}
+enum mipi_dsi_compression_algo {
+ MIPI_DSI_COMPRESSION_DSC = 0,
+ MIPI_DSI_COMPRESSION_VENDOR = 3,
+ /* other two values are reserved, DSI 1.3 */
+};
+
struct mipi_dsi_device *
mipi_dsi_device_register_full(struct mipi_dsi_host *host,
const struct mipi_dsi_device_info *info);
@@ -242,6 +248,9 @@ int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi);
int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
u16 value);
int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable);
+int mipi_dsi_compression_mode_ext(struct mipi_dsi_device *dsi, bool enable,
+ enum mipi_dsi_compression_algo algo,
+ unsigned int pps_selector);
int mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi,
const struct drm_dsc_picture_parameter_set *pps);
--
2.39.2
^ permalink raw reply related
* [PATCH v5 2/4] drm/mipi-dsi: use correct return type for the DSC functions
From: Dmitry Baryshkov @ 2024-04-07 23:53 UTC (permalink / raw)
To: Sumit Semwal, Caleb Connolly, Neil Armstrong, Jessica Zhang,
Sam Ravnborg, David Airlie, Daniel Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: dri-devel, devicetree, linux-kernel, linux-arm-msm,
Marijn Suijten
In-Reply-To: <20240408-lg-sw43408-panel-v5-0-4e092da22991@linaro.org>
The functions mipi_dsi_compression_mode() and
mipi_dsi_picture_parameter_set() return 0-or-error rather than a buffer
size. Follow example of other similar MIPI DSI functions and use int
return type instead of size_t.
Fixes: f4dea1aaa9a1 ("drm/dsi: add helpers for DSI compression mode and PPS packets")
Reviewed-by: Marijn Suijten <marijn.suijten@somainline.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/gpu/drm/drm_mipi_dsi.c | 6 +++---
include/drm/drm_mipi_dsi.h | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index ef6e416522f8..9874ff6d4718 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -654,7 +654,7 @@ EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size);
*
* Return: 0 on success or a negative error code on failure.
*/
-ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable)
+int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable)
{
/* Note: Needs updating for non-default PPS or algorithm */
u8 tx[2] = { enable << 0, 0 };
@@ -679,8 +679,8 @@ EXPORT_SYMBOL(mipi_dsi_compression_mode);
*
* Return: 0 on success or a negative error code on failure.
*/
-ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi,
- const struct drm_dsc_picture_parameter_set *pps)
+int mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi,
+ const struct drm_dsc_picture_parameter_set *pps)
{
struct mipi_dsi_msg msg = {
.channel = dsi->channel,
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index c0aec0d4d664..3011d33eccbd 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -241,9 +241,9 @@ int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi);
int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi);
int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
u16 value);
-ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable);
-ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi,
- const struct drm_dsc_picture_parameter_set *pps);
+int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable);
+int mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi,
+ const struct drm_dsc_picture_parameter_set *pps);
ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload,
size_t size);
--
2.39.2
^ permalink raw reply related
* [PATCH v5 1/4] dt-bindings: panel: Add LG SW43408 MIPI-DSI panel
From: Dmitry Baryshkov @ 2024-04-07 23:53 UTC (permalink / raw)
To: Sumit Semwal, Caleb Connolly, Neil Armstrong, Jessica Zhang,
Sam Ravnborg, David Airlie, Daniel Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: dri-devel, devicetree, linux-kernel, linux-arm-msm, Vinod Koul,
Caleb Connolly, Krzysztof Kozlowski
In-Reply-To: <20240408-lg-sw43408-panel-v5-0-4e092da22991@linaro.org>
From: Sumit Semwal <sumit.semwal@linaro.org>
LG SW43408 is 1080x2160, 4-lane MIPI-DSI panel present on Google Pixel 3
phones.
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
[caleb: convert to yaml]
Signed-off-by: Caleb Connolly <caleb@connolly.tech>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
.../bindings/display/panel/lg,sw43408.yaml | 62 ++++++++++++++++++++++
1 file changed, 62 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/panel/lg,sw43408.yaml b/Documentation/devicetree/bindings/display/panel/lg,sw43408.yaml
new file mode 100644
index 000000000000..1e08648f5bc7
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/lg,sw43408.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/lg,sw43408.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LG SW43408 1080x2160 DSI panel
+
+maintainers:
+ - Caleb Connolly <caleb.connolly@linaro.org>
+
+description:
+ This panel is used on the Pixel 3, it is a 60hz OLED panel which
+ required DSC (Display Stream Compression) and has rounded corners.
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - const: lg,sw43408
+
+ reg: true
+ port: true
+ vddi-supply: true
+ vpnl-supply: true
+ reset-gpios: true
+
+required:
+ - compatible
+ - vddi-supply
+ - vpnl-supply
+ - reset-gpios
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel@0 {
+ compatible = "lg,sw43408";
+ reg = <0>;
+
+ vddi-supply = <&vreg_l14a_1p88>;
+ vpnl-supply = <&vreg_l28a_3p0>;
+
+ reset-gpios = <&tlmm 6 GPIO_ACTIVE_LOW>;
+
+ port {
+ endpoint {
+ remote-endpoint = <&mdss_dsi0_out>;
+ };
+ };
+ };
+ };
+...
--
2.39.2
^ permalink raw reply related
* [PATCH v5 0/4] drm/panel: add support for LG SW43408 panel
From: Dmitry Baryshkov @ 2024-04-07 23:53 UTC (permalink / raw)
To: Sumit Semwal, Caleb Connolly, Neil Armstrong, Jessica Zhang,
Sam Ravnborg, David Airlie, Daniel Vetter, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: dri-devel, devicetree, linux-kernel, linux-arm-msm, Vinod Koul,
Caleb Connolly, Krzysztof Kozlowski, Marijn Suijten
The LG SW43408 panel is used on Google Pixel3 devices. For a long time
we could not submit the driver, as the panel was not coming up from the
reset. The panel seems to be picky about some of the delays during init
and it also uses non-standard payload for MIPI_DSI_COMPRESSION_MODE.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
Changes in v5:
- Mention 60 Hz in the commit message (Marijn)
- Fix the comment regarding the panel being DSC-only (Marijn)
- Link to v4: https://lore.kernel.org/r/20240403-lg-sw43408-panel-v4-0-a386d5d3b0c6@linaro.org
Changes in v4:
- Fix order of mipi_dsi_compression_mode_ext() args (Marijn)
- Expanded kerneldoc coments for this function (Marijn)
- And added arguments validation (Marijn)
- In the panel driver send the COMPRESSION_MODE in LPM mode like it was
done originally
- Expanded the .clock maths to show the reason behind the value (Marijn)
- Moved the mode out of the match data (Marijn)
- Link to v3: https://lore.kernel.org/r/20240402-lg-sw43408-panel-v3-0-144f17a11a56@linaro.org
Changes in v3:
- Fixed return type of MIPI DSC functions
- Replaced mipi_dsi_compression_mode_raw() with
mipi_dsi_compression_mode_ext() (Marijn)
- Link to v2: https://lore.kernel.org/r/20240330-lg-sw43408-panel-v2-0-293a58717b38@linaro.org
Changes in v2:
- Removed formatting char from schema (Krzysztof)
- Moved additionalProperties after required (Krzysztof)
- Added example to the schema (Krzysztof)
- Removed obsolete comment in the commit message (Marijn)
- Moved DSC params to the panel struct (Marijn)
- Changed dsc_en to be an array (Marijn)
- Added comment regiarding slice_width and slice_count (Marijn)
- Link to v1: https://lore.kernel.org/r/20240330-lg-sw43408-panel-v1-0-f5580fc9f2da@linaro.org
---
Dmitry Baryshkov (2):
drm/mipi-dsi: use correct return type for the DSC functions
drm/mipi-dsi: add mipi_dsi_compression_mode_ext()
Sumit Semwal (2):
dt-bindings: panel: Add LG SW43408 MIPI-DSI panel
drm: panel: Add LG sw43408 panel driver
.../bindings/display/panel/lg,sw43408.yaml | 62 ++++
MAINTAINERS | 8 +
drivers/gpu/drm/drm_mipi_dsi.c | 45 ++-
drivers/gpu/drm/panel/Kconfig | 11 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-lg-sw43408.c | 323 +++++++++++++++++++++
include/drm/drm_mipi_dsi.h | 15 +-
7 files changed, 453 insertions(+), 12 deletions(-)
---
base-commit: a6bd6c9333397f5a0e2667d4d82fef8c970108f2
change-id: 20240330-lg-sw43408-panel-b552f411c53e
Best regards,
--
Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox