11// SPDX-License-Identifier: GPL-2.0-only
22/* Copyright 2023 Eileen Yoon <eyn@gmx.com> */
33
4+ #include "isp-fw.h"
5+
6+ #include <asm/io.h>
47#include <linux/delay.h>
58#include <linux/pm_runtime.h>
69#include <linux/types.h>
@@ -38,6 +41,35 @@ static inline void isp_gpio_write32(struct apple_isp *isp, u32 reg, u32 val)
3841 writel (val , isp -> gpio + reg );
3942}
4043
44+ void * apple_isp_translate (struct apple_isp * isp , struct isp_surf * surf ,
45+ dma_addr_t iova , size_t size )
46+ {
47+ dma_addr_t end = iova + size ;
48+ if (!surf ) {
49+ dev_err (isp -> dev ,
50+ "Failed to translate IPC iova 0x%llx (0x%zx): No surface\n" ,
51+ (long long )iova , size );
52+ return NULL ;
53+ }
54+
55+ if (end < iova || iova < surf -> iova ||
56+ end > (surf -> iova + surf -> size )) {
57+ dev_err (isp -> dev ,
58+ "Failed to translate IPC iova 0x%llx (0x%zx): Out of bounds\n" ,
59+ (long long )iova , size );
60+ return NULL ;
61+ }
62+
63+ if (!surf -> virt ) {
64+ dev_err (isp -> dev ,
65+ "Failed to translate IPC iova 0x%llx (0x%zx): No VMap\n" ,
66+ (long long )iova , size );
67+ return NULL ;
68+ }
69+
70+ return surf -> virt + (iova - surf -> iova );
71+ }
72+
4173struct isp_firmware_bootargs {
4274 u32 pad_0 [2 ];
4375 u64 ipc_iova ;
@@ -232,13 +264,17 @@ int apple_isp_alloc_firmware_surface(struct apple_isp *isp)
232264 isp_err (isp , "failed to alloc shared surface for ipc\n" );
233265 return - ENOMEM ;
234266 }
267+ dev_info (isp -> dev , "IPC surface iova: 0x%llx\n" ,
268+ (long long )isp -> ipc_surf -> iova );
235269
236270 isp -> data_surf = isp_alloc_surface_vmap (isp , ISP_FIRMWARE_DATA_SIZE );
237271 if (!isp -> data_surf ) {
238272 isp_err (isp , "failed to alloc shared surface for data files\n" );
239273 isp_free_surface (isp , isp -> ipc_surf );
240274 return - ENOMEM ;
241275 }
276+ dev_info (isp -> dev , "Data surface iova: 0x%llx\n" ,
277+ (long long )isp -> data_surf -> iova );
242278
243279 return 0 ;
244280}
@@ -258,6 +294,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp)
258294{
259295 struct isp_firmware_bootargs args ;
260296 dma_addr_t args_iova ;
297+ void * args_virt ;
261298 int err , retries ;
262299
263300 u32 num_ipc_chans = isp_gpio_read32 (isp , ISP_GPIO_0 );
@@ -281,7 +318,9 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp)
281318 }
282319
283320 args_iova = isp -> ipc_surf -> iova + args_offset + 0x40 ;
321+ args_virt = isp -> ipc_surf -> virt + args_offset + 0x40 ;
284322 isp -> cmd_iova = args_iova + sizeof (args ) + 0x40 ;
323+ isp -> cmd_virt = args_virt + sizeof (args ) + 0x40 ;
285324
286325 memset (& args , 0 , sizeof (args ));
287326 args .ipc_iova = isp -> ipc_surf -> iova ;
@@ -295,7 +334,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp)
295334 args .unk7 = 0x1 ; // 0?
296335 args .unk_iova1 = args_iova + sizeof (args ) - 0xc ;
297336 args .unk9 = 0x3 ;
298- isp_iowrite ( isp , args_iova , & args , sizeof (args ));
337+ memcpy ( args_virt , & args , sizeof (args ));
299338
300339 isp_gpio_write32 (isp , ISP_GPIO_0 , args_iova );
301340 isp_gpio_write32 (isp , ISP_GPIO_1 , args_iova >> 32 );
@@ -355,7 +394,15 @@ static void isp_free_channel_info(struct apple_isp *isp)
355394static int isp_fill_channel_info (struct apple_isp * isp )
356395{
357396 u64 table_iova = isp_gpio_read32 (isp , ISP_GPIO_0 ) |
358- ((u64 )isp_gpio_read32 (isp , ISP_GPIO_1 )) << 32 ;
397+ ((u64 )isp_gpio_read32 (isp , ISP_GPIO_1 )) << 32 ;
398+ void * table_virt = apple_isp_ipc_translate (
399+ isp , table_iova ,
400+ sizeof (struct isp_chan_desc ) * isp -> num_ipc_chans );
401+
402+ if (!table_virt ) {
403+ dev_err (isp -> dev , "Failed to find channel table\n" );
404+ return - EIO ;
405+ }
359406
360407 isp -> ipc_chans = kcalloc (isp -> num_ipc_chans ,
361408 sizeof (struct isp_channel * ), GFP_KERNEL );
@@ -364,24 +411,31 @@ static int isp_fill_channel_info(struct apple_isp *isp)
364411
365412 for (int i = 0 ; i < isp -> num_ipc_chans ; i ++ ) {
366413 struct isp_chan_desc desc ;
367- dma_addr_t desc_iova = table_iova + (i * sizeof (desc ));
414+ void * desc_virt = table_virt + (i * sizeof (desc ));
368415 struct isp_channel * chan =
369416 kzalloc (sizeof (struct isp_channel ), GFP_KERNEL );
370417 if (!chan )
371418 goto out ;
372419 isp -> ipc_chans [i ] = chan ;
373420
374- isp_ioread ( isp , desc_iova , & desc , sizeof (desc ));
421+ memcpy ( & desc , desc_virt , sizeof (desc ));
375422 chan -> name = kstrdup (desc .name , GFP_KERNEL );
376423 chan -> type = desc .type ;
377424 chan -> src = desc .src ;
378425 chan -> doorbell = 1 << chan -> src ;
379426 chan -> num = desc .num ;
380427 chan -> size = desc .num * ISP_IPC_MESSAGE_SIZE ;
381428 chan -> iova = desc .iova ;
429+ chan -> virt =
430+ apple_isp_ipc_translate (isp , desc .iova , chan -> size );
382431 chan -> cursor = 0 ;
383432 spin_lock_init (& chan -> lock );
384433
434+ if (!chan -> virt ) {
435+ dev_err (isp -> dev , "Failed to find channel buffer\n" );
436+ goto out ;
437+ }
438+
385439 if ((chan -> type != ISP_IPC_CHAN_TYPE_COMMAND ) &&
386440 (chan -> type != ISP_IPC_CHAN_TYPE_REPLY ) &&
387441 (chan -> type != ISP_IPC_CHAN_TYPE_REPORT )) {
@@ -439,11 +493,11 @@ static int isp_firmware_boot_stage3(struct apple_isp *isp)
439493 continue ;
440494 for (int j = 0 ; j < chan -> num ; j ++ ) {
441495 struct isp_message msg ;
442- dma_addr_t msg_iova = chan -> iova + (j * sizeof (msg ));
496+ void * msg_virt = chan -> virt + (j * sizeof (msg ));
443497
444498 memset (& msg , 0 , sizeof (msg ));
445499 msg .arg0 = ISP_IPC_FLAG_ACK ;
446- isp_iowrite ( isp , msg_iova , & msg , sizeof (msg ));
500+ memcpy ( msg_virt , & msg , sizeof (msg ));
447501 }
448502 }
449503 wmb ();
@@ -547,6 +601,10 @@ static int isp_start_command_processor(struct apple_isp *isp)
547601static void isp_collect_gc_surface (struct apple_isp * isp )
548602{
549603 struct isp_surf * tmp , * surf ;
604+
605+ isp -> log_surf = NULL ;
606+ isp -> bt_surf = NULL ;
607+
550608 list_for_each_entry_safe_reverse (surf , tmp , & isp -> gc , head ) {
551609 isp_dbg (isp , "freeing iova: 0x%llx size: 0x%llx virt: %pS\n" ,
552610 surf -> iova , surf -> size , (void * )surf -> virt );
0 commit comments