LCOV - code coverage report
Current view: top level - ipu4 - ipu6.c (source / functions) Coverage Total Hit
Test: ipu4.info Lines: 46.3 % 255 118
Test Date: 2026-05-12 04:57:36 Functions: 64.3 % 14 9

            Line data    Source code
       1              : // SPDX-License-Identifier: GPL-2.0-only
       2              : /*
       3              :  * Copyright (C) 2013--2024 Intel Corporation
       4              :  */
       5              : 
       6              : #include <linux/bitfield.h>
       7              : #include <linux/bits.h>
       8              : #include <linux/dma-mapping.h>
       9              : #include <linux/err.h>
      10              : #include <linux/firmware.h>
      11              : #include <linux/kernel.h>
      12              : #include <linux/interrupt.h>
      13              : #include <linux/io.h>
      14              : #include <linux/list.h>
      15              : #include <linux/module.h>
      16              : #include <linux/pci-ats.h>
      17              : #include <linux/pm_runtime.h>
      18              : #include <linux/property.h>
      19              : #include <linux/scatterlist.h>
      20              : #include <linux/slab.h>
      21              : #include <linux/types.h>
      22              : 
      23              : #ifdef IPU6
      24              : #include <media/ipu-bridge.h>
      25              : #include <media/ipu6-pci-table.h>
      26              : #else
      27              : #include "ambu-ipu-bridge.h"
      28              : #include "virt-sensor.h"
      29              : #endif
      30              : 
      31              : #include "ipu6.h"
      32              : #include "ipu6-bus.h"
      33              : #include "ipu6-buttress.h"
      34              : #include "ipu6-cpd.h"
      35              : #include "ipu6-isys.h"
      36              : #include "ipu6-mmu.h"
      37              : #include "ipu6-platform-buttress-regs.h"
      38              : #include "ipu6-platform-isys-csi2-reg.h"
      39              : #include "ipu6-platform-regs.h"
      40              : 
      41              : #define IPU6_PCI_BAR            0
      42              : 
      43              : struct ipu6_cell_program {
      44              :         u32 magic_number;
      45              : 
      46              :         u32 blob_offset;
      47              :         u32 blob_size;
      48              : 
      49              :         u32 start[3];
      50              : 
      51              :         u32 icache_source;
      52              :         u32 icache_target;
      53              :         u32 icache_size;
      54              : 
      55              :         u32 pmem_source;
      56              :         u32 pmem_target;
      57              :         u32 pmem_size;
      58              : 
      59              :         u32 data_source;
      60              :         u32 data_target;
      61              :         u32 data_size;
      62              : 
      63              :         u32 bss_target;
      64              :         u32 bss_size;
      65              : 
      66              :         u32 cell_id;
      67              :         u32 regs_addr;
      68              : 
      69              :         u32 cell_pmem_data_bus_address;
      70              :         u32 cell_dmem_data_bus_address;
      71              :         u32 cell_pmem_control_bus_address;
      72              :         u32 cell_dmem_control_bus_address;
      73              : 
      74              :         u32 next;
      75              :         u32 dummy[2];
      76              : };
      77              : 
      78              : #ifdef IPU6
      79              : static struct ipu6_isys_internal_pdata isys_ipdata = {
      80              :         .hw_variant = {
      81              :                 .offset = IPU6_UNIFIED_OFFSET,
      82              :                 .nr_mmus = 3,
      83              :                 .mmu_hw = {
      84              :                         {
      85              :                                 .offset = IPU6_ISYS_IOMMU0_OFFSET,
      86              :                                 .info_bits = IPU6_INFO_REQUEST_DESTINATION_IOSF,
      87              :                                 .nr_l1streams = 16,
      88              :                                 .l1_block_sz = {
      89              :                                         3, 8, 2, 2, 2, 2, 2, 2, 1, 1,
      90              :                                         1, 1, 1, 1, 1, 1
      91              :                                 },
      92              :                                 .nr_l2streams = 16,
      93              :                                 .l2_block_sz = {
      94              :                                         2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
      95              :                                         2, 2, 2, 2, 2, 2
      96              :                                 },
      97              :                                 .insert_read_before_invalidate = false,
      98              :                                 .l1_stream_id_reg_offset =
      99              :                                 IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
     100              :                                 .l2_stream_id_reg_offset =
     101              :                                 IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
     102              :                         },
     103              :                         {
     104              :                                 .offset = IPU6_ISYS_IOMMU1_OFFSET,
     105              :                                 .info_bits = 0,
     106              :                                 .nr_l1streams = 16,
     107              :                                 .l1_block_sz = {
     108              :                                         2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     109              :                                         2, 2, 2, 1, 1, 4
     110              :                                 },
     111              :                                 .nr_l2streams = 16,
     112              :                                 .l2_block_sz = {
     113              :                                         2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     114              :                                         2, 2, 2, 2, 2, 2
     115              :                                 },
     116              :                                 .insert_read_before_invalidate = false,
     117              :                                 .l1_stream_id_reg_offset =
     118              :                                 IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
     119              :                                 .l2_stream_id_reg_offset =
     120              :                                 IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
     121              :                         },
     122              :                         {
     123              :                                 .offset = IPU6_ISYS_IOMMUI_OFFSET,
     124              :                                 .info_bits = 0,
     125              :                                 .nr_l1streams = 0,
     126              :                                 .nr_l2streams = 0,
     127              :                                 .insert_read_before_invalidate = false,
     128              :                         },
     129              :                 },
     130              :                 .cdc_fifos = 3,
     131              :                 .cdc_fifo_threshold = {6, 8, 2},
     132              :                 .dmem_offset = IPU6_ISYS_DMEM_OFFSET,
     133              :                 .spc_offset = IPU6_ISYS_SPC_OFFSET,
     134              :         },
     135              :         .isys_dma_overshoot = IPU6_ISYS_OVERALLOC_MIN,
     136              : };
     137              : 
     138              : static struct ipu6_psys_internal_pdata psys_ipdata = {
     139              :         .hw_variant = {
     140              :                 .offset = IPU6_UNIFIED_OFFSET,
     141              :                 .nr_mmus = 4,
     142              :                 .mmu_hw = {
     143              :                         {
     144              :                                 .offset = IPU6_PSYS_IOMMU0_OFFSET,
     145              :                                 .info_bits =
     146              :                                 IPU6_INFO_REQUEST_DESTINATION_IOSF,
     147              :                                 .nr_l1streams = 16,
     148              :                                 .l1_block_sz = {
     149              :                                         2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     150              :                                         2, 2, 2, 2, 2, 2
     151              :                                 },
     152              :                                 .nr_l2streams = 16,
     153              :                                 .l2_block_sz = {
     154              :                                         2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     155              :                                         2, 2, 2, 2, 2, 2
     156              :                                 },
     157              :                                 .insert_read_before_invalidate = false,
     158              :                                 .l1_stream_id_reg_offset =
     159              :                                 IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
     160              :                                 .l2_stream_id_reg_offset =
     161              :                                 IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
     162              :                         },
     163              :                         {
     164              :                                 .offset = IPU6_PSYS_IOMMU1_OFFSET,
     165              :                                 .info_bits = 0,
     166              :                                 .nr_l1streams = 32,
     167              :                                 .l1_block_sz = {
     168              :                                         1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     169              :                                         2, 2, 2, 2, 2, 10,
     170              :                                         5, 4, 14, 6, 4, 14, 6, 4, 8,
     171              :                                         4, 2, 1, 1, 1, 1, 14
     172              :                                 },
     173              :                                 .nr_l2streams = 32,
     174              :                                 .l2_block_sz = {
     175              :                                         2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     176              :                                         2, 2, 2, 2, 2, 2,
     177              :                                         2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     178              :                                         2, 2, 2, 2, 2, 2
     179              :                                 },
     180              :                                 .insert_read_before_invalidate = false,
     181              :                                 .l1_stream_id_reg_offset =
     182              :                                 IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
     183              :                                 .l2_stream_id_reg_offset =
     184              :                                 IPU6_PSYS_MMU1W_L2_STREAM_ID_REG_OFFSET,
     185              :                         },
     186              :                         {
     187              :                                 .offset = IPU6_PSYS_IOMMU1R_OFFSET,
     188              :                                 .info_bits = 0,
     189              :                                 .nr_l1streams = 16,
     190              :                                 .l1_block_sz = {
     191              :                                         1, 4, 4, 4, 4, 16, 8, 4, 32,
     192              :                                         16, 16, 2, 2, 2, 1, 12
     193              :                                 },
     194              :                                 .nr_l2streams = 16,
     195              :                                 .l2_block_sz = {
     196              :                                         2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     197              :                                         2, 2, 2, 2, 2, 2
     198              :                                 },
     199              :                                 .insert_read_before_invalidate = false,
     200              :                                 .l1_stream_id_reg_offset =
     201              :                                 IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
     202              :                                 .l2_stream_id_reg_offset =
     203              :                                 IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
     204              :                         },
     205              :                         {
     206              :                                 .offset = IPU6_PSYS_IOMMUI_OFFSET,
     207              :                                 .info_bits = 0,
     208              :                                 .nr_l1streams = 0,
     209              :                                 .nr_l2streams = 0,
     210              :                                 .insert_read_before_invalidate = false,
     211              :                         },
     212              :                 },
     213              :                 .dmem_offset = IPU6_PSYS_DMEM_OFFSET,
     214              :         },
     215              : };
     216              : #else
     217              : static const struct ipu6_isys_internal_pdata isys_ipdata = {
     218              :         .hw_variant = {
     219              :             .offset = IPU4_ISYS_OFFSET,
     220              :                 .nr_mmus = 2,
     221              :                 .mmu_hw = {{
     222              :                         .offset = IPU4_ISYS_IOMMU0_OFFSET,
     223              :                         .info_bits = IPU4_INFO_REQUEST_DESTINATION_PRIMARY,
     224              :                         .nr_l1streams = 0,
     225              :                         .nr_l2streams = 0,
     226              :                         .insert_read_before_invalidate = true,
     227              :                         },
     228              :                         {
     229              :                         .offset = IPU4_ISYS_IOMMU1_OFFSET,
     230              :                         .info_bits = IPU4_INFO_STREAM_ID_SET(0),
     231              :                         .nr_l1streams = IPU4_MMU_MAX_TLB_L1_STREAMS,
     232              :                         .l1_block_sz = {
     233              :                                         8, 16, 16, 16, 0, 0, 0, 0, 0,
     234              :                                         0, 0, 0, 0, 0, 0, 8
     235              :                         },
     236              :                         .l1_zlw_en = {
     237              :                                         1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
     238              :                                         0, 0, 0, 0, 0, 0
     239              :                         },
     240              :                         .l1_zlw_1d_mode = {
     241              :                                         0, 1, 1, 1, 0, 0, 0, 0,
     242              :                                         0, 0, 0, 0, 0, 0, 0, 0
     243              :                         },
     244              :                         .l1_ins_zlw_ahead_pages = {
     245              :                                                 0, 3, 3, 3, 0, 0,
     246              :                                                 0, 0, 0, 0, 0, 0,
     247              :                                                 0, 0, 0, 0
     248              :                         },
     249              :                         .l1_zlw_2d_mode = {
     250              :                                         0, 0, 0, 0, 0, 0, 0, 0, 0,
     251              :                                         0, 0, 0, 0, 0, 0, 0
     252              :                         },
     253              :                         .nr_l2streams = IPU4_MMU_MAX_TLB_L2_STREAMS,
     254              :                         .l2_block_sz = {
     255              :                                         2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     256              :                                         2, 2, 2, 2, 2, 2
     257              :                         },
     258              :                         .insert_read_before_invalidate = false,
     259              :                         .zlw_invalidate = false,
     260              :                         .l1_stream_id_reg_offset =
     261              :                                 IPU4_MMU_L1_STREAM_ID_REG_OFFSET,
     262              :                         .l2_stream_id_reg_offset =
     263              :                                 IPU4_MMU_L2_STREAM_ID_REG_OFFSET,
     264              :                         },
     265              :                 },
     266              :                 .dmem_offset = IPU4_ISYS_DMEM_OFFSET,
     267              :                 .spc_offset = IPU4_ISYS_SPC_OFFSET,
     268              :         },
     269              :         .isys_dma_overshoot = IPU6_ISYS_OVERALLOC_MIN,
     270              :         .num_parallel_streams = IPU4_STREAM_ID_MAX,
     271              :         .csi2.nports = ARRAY_SIZE(ipu4_csi_offsets),
     272              :         .max_streams = IPU4_ISYS_MAX_STREAMS,
     273              :         .max_sram_blocks = IPU4_ISYS_MAX_STREAMS,
     274              :         .max_send_queues = IPU4_N_MAX_SEND_QUEUES,
     275              : 
     276              :         /* Consider 1 slot per stream since driver is not expected to pipeline
     277              :          * device commands for the same stream
     278              :          */
     279              :         .max_devq_size = IPU4_ISYS_MAX_STREAMS,
     280              : };
     281              : 
     282              : static const struct ipu6_psys_internal_pdata psys_ipdata = {
     283              :         .hw_variant = {
     284              :                        .offset = IPU4_PSYS_OFFSET,
     285              :                        .nr_mmus = 3,
     286              :                        .mmu_hw = {
     287              :                                 {
     288              :                                    .offset = IPU4_PSYS_IOMMU0_OFFSET,
     289              :                                    .info_bits =
     290              :                                    IPU4_INFO_REQUEST_DESTINATION_PRIMARY,
     291              :                                    .nr_l1streams = 0,
     292              :                                    .nr_l2streams = 0,
     293              :                                    .insert_read_before_invalidate = true,
     294              :                                 },
     295              :                                 {
     296              :                                    .offset = IPU4_PSYS_IOMMU1_OFFSET,
     297              :                                    .info_bits = IPU4_INFO_STREAM_ID_SET(0),
     298              :                                    .nr_l1streams = IPU4_MMU_MAX_TLB_L1_STREAMS,
     299              :                                    .l1_block_sz = {
     300              :                                                    0, 0, 0, 0, 10, 8, 10, 8, 0,
     301              :                                                    4, 4, 12, 0, 0, 0, 8
     302              :                                    },
     303              :                                    .l1_zlw_en = {
     304              :                                                  0, 0, 0, 0, 1, 1, 1, 1, 0, 1,
     305              :                                                  1, 1, 0, 0, 0, 0
     306              :                                    },
     307              :                                    .l1_zlw_1d_mode = {
     308              :                                                       0, 0, 0, 0, 1, 1, 1, 1, 0,
     309              :                                                       1, 1, 1, 0, 0, 0, 0
     310              :                                    },
     311              :                                    .l1_ins_zlw_ahead_pages = {
     312              :                                                               0, 0, 0, 0, 3, 3,
     313              :                                                               3, 3, 0, 3, 1, 3,
     314              :                                                               0, 0, 0, 0
     315              :                                    },
     316              :                                    .l1_zlw_2d_mode = {
     317              :                                                       0, 0, 0, 0, 0, 0, 0, 0, 0,
     318              :                                                       0, 0, 0, 0, 0, 0, 0
     319              :                                    },
     320              :                                    .nr_l2streams = IPU4_MMU_MAX_TLB_L2_STREAMS,
     321              :                                    .l2_block_sz = {
     322              :                                                    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     323              :                                                    2, 2, 2, 2, 2, 2
     324              :                                    },
     325              :                                    .insert_read_before_invalidate = false,
     326              :                                    .zlw_invalidate = false,
     327              :                                    .l1_stream_id_reg_offset =
     328              :                                    IPU4_MMU_L1_STREAM_ID_REG_OFFSET,
     329              :                                    .l2_stream_id_reg_offset =
     330              :                                    IPU4_MMU_L2_STREAM_ID_REG_OFFSET,
     331              :                                 },
     332              :                                 {
     333              :                                    .offset = IPU4_PSYS_IOMMU1R_OFFSET,
     334              :                                    .info_bits = IPU4_INFO_STREAM_ID_SET(0),
     335              :                                    .nr_l1streams = IPU4_MMU_MAX_TLB_L1_STREAMS,
     336              :                                    .l1_block_sz = {
     337              :                                                    0, 0, 0, 0, 0, 0, 0, 0, 8, 0,
     338              :                                                    0, 0, 16, 12, 12, 16
     339              :                                    },
     340              :                                    .l1_zlw_en = {
     341              :                                                  0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
     342              :                                                  0, 0, 1, 1, 1, 1
     343              :                                    },
     344              :                                    .l1_zlw_1d_mode = {
     345              :                                                       0, 0, 0, 0, 0, 0, 0, 0, 1,
     346              :                                                       0, 0, 0, 0, 1, 1, 1
     347              :                                    },
     348              :                                    .l1_ins_zlw_ahead_pages = {
     349              :                                                               0, 0, 0, 0, 0, 0,
     350              :                                                               0, 0, 3, 0, 0, 0,
     351              :                                                               0, 0, 0, 0
     352              :                                    },
     353              :                                    .l1_zlw_2d_mode = {
     354              :                                                       0, 0, 0, 0, 0, 0, 0, 0, 0,
     355              :                                                       0, 0, 0, 0, 1, 1, 1
     356              :                                    },
     357              :                                    .nr_l2streams = IPU4_MMU_MAX_TLB_L2_STREAMS,
     358              :                                    .l2_block_sz = {
     359              :                                                    2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
     360              :                                                    2, 2, 2, 2, 2, 2
     361              :                                    },
     362              :                                    .insert_read_before_invalidate = false,
     363              :                                    .zlw_invalidate = false,
     364              :                                    .l1_stream_id_reg_offset =
     365              :                                    IPU4_MMU_L1_STREAM_ID_REG_OFFSET,
     366              :                                    .l2_stream_id_reg_offset =
     367              :                                    IPU4_MMU_L2_STREAM_ID_REG_OFFSET,
     368              :                                 },
     369              :                         },
     370              :                        .dmem_offset = IPU4_PSYS_DMEM_OFFSET,
     371              :                        .spc_offset = IPU4_PSYS_SPC_OFFSET,
     372              :         },
     373              : };
     374              : #endif
     375              : 
     376              : static const struct ipu6_buttress_ctrl ipu6_isys_buttress_ctrl = {
     377              :         .ratio = IPU6_IS_FREQ_CTL_DEFAULT_RATIO,
     378              :         .qos_floor = IPU6_IS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
     379              :         .freq_ctl = IPU6_BUTTRESS_REG_IS_FREQ_CTL,
     380              :         .pwr_sts_shift = IPU6_BUTTRESS_PWR_STATE_IS_PWR_SHIFT,
     381              :         .pwr_sts_mask = IPU6_BUTTRESS_PWR_STATE_IS_PWR_MASK,
     382              :         .pwr_sts_on = IPU6_BUTTRESS_PWR_STATE_UP_DONE,
     383              :         .pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
     384              : };
     385              : 
     386              : static const struct ipu6_buttress_ctrl ipu6_psys_buttress_ctrl = {
     387              :         .ratio = IPU6_PS_FREQ_CTL_DEFAULT_RATIO,
     388              :         .qos_floor = IPU6_PS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
     389              :         .freq_ctl = IPU6_BUTTRESS_REG_PS_FREQ_CTL,
     390              :         .pwr_sts_shift = IPU6_BUTTRESS_PWR_STATE_PS_PWR_SHIFT,
     391              :         .pwr_sts_mask = IPU6_BUTTRESS_PWR_STATE_PS_PWR_MASK,
     392              :         .pwr_sts_on = IPU6_BUTTRESS_PWR_STATE_UP_DONE,
     393              :         .pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
     394              : };
     395              : 
     396              : /* Non-static: declared extern in ipu6.h so ipu4_buttress_math_kunit
     397              :  * can pin every field against the IPU4 platform constants. The struct
     398              :  * uses designated initializers, so what the kunit catches is value
     399              :  * drift in the bindings — not struct-layout reorders, which are
     400              :  * compiler no-ops.
     401              :  */
     402              : const struct ipu6_buttress_ctrl ipu4_isys_buttress_ctrl = {
     403              :         .ratio = IPU4_IS_FREQ_CTL_DIVISOR,
     404              :         .qos_floor = 0,
     405              :         .freq_ctl = IPU6_BUTTRESS_REG_IS_FREQ_CTL,
     406              :         .pwr_sts_shift = IPU4_BUTTRESS_PWR_STATE_IS_PWR_FSM_SHIFT,
     407              :         .pwr_sts_mask = IPU4_BUTTRESS_PWR_STATE_IS_PWR_FSM_MASK,
     408              :         .pwr_sts_on = IPU4_BUTTRESS_PWR_STATE_IS_PWR_FSM_IS_RDY,
     409              :         .pwr_sts_off = IPU4_BUTTRESS_PWR_STATE_IS_PWR_FSM_IDLE,
     410              : };
     411              : 
     412              : const struct ipu6_buttress_ctrl ipu4_psys_buttress_ctrl = {
     413              :         .ratio = IPU4_PS_FREQ_CTL_DEFAULT_RATIO,
     414              :         .qos_floor = IPU4_PS_FREQ_CTL_DEFAULT_RATIO,
     415              :         .freq_ctl = IPU6_BUTTRESS_REG_PS_FREQ_CTL,
     416              :         .pwr_sts_shift = IPU4_BUTTRESS_PWR_STATE_PS_PWR_FSM_SHIFT,
     417              :         .pwr_sts_mask = IPU4_BUTTRESS_PWR_STATE_PS_PWR_FSM_MASK,
     418              :         .pwr_sts_on = IPU4_BUTTRESS_PWR_STATE_PS_PWR_FSM_PS_PWR_UP,
     419              :         .pwr_sts_off = IPU4_BUTTRESS_PWR_STATE_PS_PWR_FSM_IDLE,
     420              : };
     421              : 
     422              : static void
     423            0 : ipu6_pkg_dir_configure_spc(struct ipu6_device *isp,
     424              :                            const struct ipu6_hw_variants *hw_variant,
     425              :                            int pkg_dir_idx, void __iomem *base,
     426              :                            u64 *pkg_dir, dma_addr_t pkg_dir_vied_address)
     427              : {
     428              :         struct ipu6_cell_program *prog;
     429              :         void __iomem *spc_base;
     430              :         u32 server_fw_addr;
     431              :         dma_addr_t dma_addr;
     432              :         u32 pg_offset;
     433              : 
     434            0 :         server_fw_addr = lower_32_bits(*(pkg_dir + (pkg_dir_idx + 1) * 2));
     435              :         /*
     436              :          * The stub CPD blob shipped by tools/firmware/gen-cpd.py has
     437              :          * zeroed pkg_dir entries — enough to satisfy
     438              :          * ipu6_cpd_validate_cpd_file() but not to point at a real SPC
     439              :          * program. Walking the cell_program at the resulting wild
     440              :          * pointer would deref invalid memory. Skip the SPC-program
     441              :          * load when there's nothing to load; the QEMU device model
     442              :          * just absorbs the SPC writes that did fire and the syscom
     443              :          * boot handshake completes via the model's SYSCOM_STATE
     444              :          * shortcut.
     445              :          */
     446            0 :         if (!server_fw_addr) {
     447            0 :                 dev_dbg(&isp->pdev->dev,
     448              :                         "skipping SPC program load: empty pkg_dir entry %d\n",
     449              :                         pkg_dir_idx);
     450            0 :                 return;
     451              :         }
     452            0 :         if (pkg_dir_idx == IPU6_CPD_PKG_DIR_ISYS_SERVER_IDX)
     453            0 :                 dma_addr = sg_dma_address(isp->isys->fw_sgt.sgl);
     454              :         else
     455            0 :                 dma_addr = sg_dma_address(isp->psys->fw_sgt.sgl);
     456              : 
     457            0 :         pg_offset = server_fw_addr - dma_addr;
     458            0 :         prog = (struct ipu6_cell_program *)((uintptr_t)isp->cpd_fw->data +
     459              :                                             pg_offset);
     460            0 :         spc_base = base + prog->regs_addr;
     461            0 :         if (spc_base != (base + hw_variant->spc_offset))
     462            0 :                 dev_warn(&isp->pdev->dev,
     463              :                          "SPC reg addr %p not matching value from CPD %p\n",
     464              :                          base + hw_variant->spc_offset, spc_base);
     465            0 :         writel(server_fw_addr + prog->blob_offset +
     466            0 :                prog->icache_source, spc_base + IPU6_PSYS_REG_SPC_ICACHE_BASE);
     467              :         writel(IPU6_INFO_REQUEST_DESTINATION_IOSF,
     468            0 :                spc_base + IPU6_REG_PSYS_INFO_SEG_0_CONFIG_ICACHE_MASTER);
     469            0 :         writel(prog->start[1], spc_base + IPU6_PSYS_REG_SPC_START_PC);
     470            0 :         writel(pkg_dir_vied_address, base + hw_variant->dmem_offset);
     471              : }
     472              : 
     473            1 : void ipu6_configure_spc(struct ipu6_device *isp,
     474              :                         const struct ipu6_hw_variants *hw_variant,
     475              :                         int pkg_dir_idx, void __iomem *base, u64 *pkg_dir,
     476              :                         dma_addr_t pkg_dir_dma_addr)
     477              : {
     478            1 :         void __iomem *dmem_base = base + hw_variant->dmem_offset;
     479            1 :         void __iomem *spc_regs_base = base + hw_variant->spc_offset;
     480              :         u32 val;
     481              : 
     482              :         val = readl(spc_regs_base + IPU6_PSYS_REG_SPC_STATUS_CTRL);
     483            1 :         val |= IPU6_PSYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE;
     484              :         writel(val, spc_regs_base + IPU6_PSYS_REG_SPC_STATUS_CTRL);
     485              : 
     486            1 :         if (isp->secure_mode)
     487              :                 writel(IPU6_PKG_DIR_IMR_OFFSET, dmem_base);
     488              :         else
     489            0 :                 ipu6_pkg_dir_configure_spc(isp, hw_variant, pkg_dir_idx, base,
     490              :                                            pkg_dir, pkg_dir_dma_addr);
     491            1 : }
     492              : EXPORT_SYMBOL_NS_GPL(ipu6_configure_spc, INTEL_IPU6);
     493              : 
     494            1 : static int ipu6_isys_check_fwnode_graph(struct fwnode_handle *fwnode)
     495              : {
     496              :         struct fwnode_handle *endpoint;
     497              : 
     498              :         if (IS_ERR_OR_NULL(fwnode))
     499              :                 return -EINVAL;
     500              : 
     501            1 :         endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL);
     502            1 :         if (endpoint) {
     503            0 :                 fwnode_handle_put(endpoint);
     504            0 :                 return 0;
     505              :         }
     506              : 
     507            1 :         return ipu6_isys_check_fwnode_graph(fwnode->secondary);
     508              : }
     509              : 
     510              : #define IPU6_ISYS_CSI2_NPORTS           4
     511              : #define IPU6SE_ISYS_CSI2_NPORTS         4
     512              : #define IPU6_TGL_ISYS_CSI2_NPORTS       8
     513              : #define IPU6EP_MTL_ISYS_CSI2_NPORTS     6
     514              : 
     515              : static void ipu6_internal_pdata_init(struct ipu6_device *isp)
     516              : {
     517              : #ifdef IPU6
     518              :         u8 hw_ver = isp->hw_ver;
     519              : 
     520              :         isys_ipdata.num_parallel_streams = IPU6_ISYS_NUM_STREAMS;
     521              :         isys_ipdata.sram_gran_shift = IPU6_SRAM_GRANULARITY_SHIFT;
     522              :         isys_ipdata.sram_gran_size = IPU6_SRAM_GRANULARITY_SIZE;
     523              :         isys_ipdata.max_sram_size = IPU6_MAX_SRAM_SIZE;
     524              :         isys_ipdata.sensor_type_start = IPU6_FW_ISYS_SENSOR_TYPE_START;
     525              :         isys_ipdata.sensor_type_end = IPU6_FW_ISYS_SENSOR_TYPE_END;
     526              :         isys_ipdata.max_streams = IPU6_ISYS_NUM_STREAMS;
     527              :         isys_ipdata.max_send_queues = IPU6_N_MAX_SEND_QUEUES;
     528              :         isys_ipdata.max_sram_blocks = IPU6_NOF_SRAM_BLOCKS_MAX;
     529              :         isys_ipdata.max_devq_size = IPU6_DEV_SEND_QUEUE_SIZE;
     530              :         isys_ipdata.csi2.nports = IPU6_ISYS_CSI2_NPORTS;
     531              :         isys_ipdata.csi2.irq_mask = IPU6_CSI_RX_ERROR_IRQ_MASK;
     532              :         isys_ipdata.csi2.ctrl0_irq_edge = IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_EDGE;
     533              :         isys_ipdata.csi2.ctrl0_irq_clear =
     534              :                 IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR;
     535              :         isys_ipdata.csi2.ctrl0_irq_mask = IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_MASK;
     536              :         isys_ipdata.csi2.ctrl0_irq_enable =
     537              :                 IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_ENABLE;
     538              :         isys_ipdata.csi2.ctrl0_irq_status =
     539              :                 IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS;
     540              :         isys_ipdata.csi2.ctrl0_irq_lnp =
     541              :                 IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE;
     542              :         isys_ipdata.enhanced_iwake = is_ipu6ep_mtl(hw_ver) || is_ipu6ep(hw_ver);
     543              :         psys_ipdata.hw_variant.spc_offset = IPU6_PSYS_SPC_OFFSET;
     544              :         isys_ipdata.csi2.fw_access_port_ofs = CSI_REG_HUB_FW_ACCESS_PORT_OFS;
     545              : 
     546              :         if (is_ipu6ep(hw_ver)) {
     547              :                 isys_ipdata.ltr = IPU6EP_LTR_VALUE;
     548              :                 isys_ipdata.memopen_threshold = IPU6EP_MIN_MEMOPEN_TH;
     549              :         }
     550              : 
     551              :         if (is_ipu6_tgl(hw_ver))
     552              :                 isys_ipdata.csi2.nports = IPU6_TGL_ISYS_CSI2_NPORTS;
     553              : 
     554              :         if (is_ipu6ep_mtl(hw_ver)) {
     555              :                 isys_ipdata.csi2.nports = IPU6EP_MTL_ISYS_CSI2_NPORTS;
     556              : 
     557              :                 isys_ipdata.csi2.ctrl0_irq_edge =
     558              :                         IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_EDGE;
     559              :                 isys_ipdata.csi2.ctrl0_irq_clear =
     560              :                         IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR;
     561              :                 isys_ipdata.csi2.ctrl0_irq_mask =
     562              :                         IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_MASK;
     563              :                 isys_ipdata.csi2.ctrl0_irq_enable =
     564              :                         IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_ENABLE;
     565              :                 isys_ipdata.csi2.ctrl0_irq_lnp =
     566              :                         IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE;
     567              :                 isys_ipdata.csi2.ctrl0_irq_status =
     568              :                         IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS;
     569              :                 isys_ipdata.csi2.fw_access_port_ofs =
     570              :                         CSI_REG_HUB_FW_ACCESS_PORT_V6OFS;
     571              :                 isys_ipdata.ltr = IPU6EP_MTL_LTR_VALUE;
     572              :                 isys_ipdata.memopen_threshold = IPU6EP_MTL_MIN_MEMOPEN_TH;
     573              :         }
     574              : 
     575              :         if (is_ipu6se(hw_ver)) {
     576              :                 isys_ipdata.csi2.nports = IPU6SE_ISYS_CSI2_NPORTS;
     577              :                 isys_ipdata.csi2.irq_mask = IPU6SE_CSI_RX_ERROR_IRQ_MASK;
     578              :                 isys_ipdata.num_parallel_streams = IPU6SE_ISYS_NUM_STREAMS;
     579              :                 isys_ipdata.sram_gran_shift = IPU6SE_SRAM_GRANULARITY_SHIFT;
     580              :                 isys_ipdata.sram_gran_size = IPU6SE_SRAM_GRANULARITY_SIZE;
     581              :                 isys_ipdata.max_sram_size = IPU6SE_MAX_SRAM_SIZE;
     582              :                 isys_ipdata.sensor_type_start =
     583              :                         IPU6SE_FW_ISYS_SENSOR_TYPE_START;
     584              :                 isys_ipdata.sensor_type_end = IPU6SE_FW_ISYS_SENSOR_TYPE_END;
     585              :                 isys_ipdata.max_streams = IPU6SE_ISYS_NUM_STREAMS;
     586              :                 isys_ipdata.max_send_queues = IPU6SE_N_MAX_SEND_QUEUES;
     587              :                 isys_ipdata.max_sram_blocks = IPU6SE_NOF_SRAM_BLOCKS_MAX;
     588              :                 isys_ipdata.max_devq_size = IPU6SE_DEV_SEND_QUEUE_SIZE;
     589              :                 psys_ipdata.hw_variant.spc_offset = IPU6SE_PSYS_SPC_OFFSET;
     590              :         }
     591              : #else
     592              :         (void)isp;
     593              : #endif
     594              : }
     595              : 
     596              : static struct ipu6_bus_device *
     597            1 : ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
     598              :                const struct ipu6_buttress_ctrl *ctrl, void __iomem *base,
     599              :                const struct ipu6_isys_internal_pdata *ipdata)
     600              : {
     601              : #ifndef IPU6
     602            1 :         struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev);
     603              : #endif
     604              :         struct device *dev = &pdev->dev;
     605              :         struct ipu6_bus_device *isys_adev;
     606              :         struct ipu6_isys_pdata *pdata;
     607              :         int ret;
     608              : 
     609              : #ifdef IPU6
     610              :         ret = ipu_bridge_init(dev, ipu_bridge_parse_ssdb);
     611              :         if (ret) {
     612              :                 dev_err_probe(dev, ret, "IPU6 bridge init failed\n");
     613              :                 return ERR_PTR(ret);
     614              :         }
     615              : #else
     616              :         /* check fwnode at first, fallback into bridge if no fwnode graph */
     617            1 :         ret = ipu6_isys_check_fwnode_graph(fwnode);
     618            1 :         if (ret) {
     619            2 :                 if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary)) {
     620            0 :                         dev_err(&pdev->dev,
     621              :                                 "fwnode graph has no endpoints connection\n");
     622            0 :                         return ERR_PTR(-EINVAL);
     623              :                 }
     624              : 
     625              : #if IS_ENABLED(CONFIG_VIDEO_IPU4_VIRT_SENSOR)
     626            1 :                 ret = ipu4_virt_sensor_install(pdev);
     627              : #else
     628              :                 ret = ambu_ipu_bridge_init(dev);
     629              : #endif
     630            1 :                 if (ret) {
     631            0 :                         if (ret != -EPROBE_DEFER)
     632            0 :                                 dev_err_probe(dev, ret, "IPU6 bridge init failed\n");
     633            0 :                         return ERR_PTR(ret);
     634              :                 }
     635              :         }
     636              : #endif
     637              : 
     638            1 :         pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
     639            1 :         if (!pdata)
     640              :                 return ERR_PTR(-ENOMEM);
     641              : 
     642            1 :         pdata->base = base;
     643            1 :         pdata->ipdata = ipdata;
     644              : 
     645            1 :         isys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, ctrl,
     646              :                                                IPU6_ISYS_NAME);
     647            1 :         if (IS_ERR(isys_adev)) {
     648            0 :                 kfree(pdata);
     649            0 :                 return dev_err_cast_probe(dev, isys_adev,
     650              :                                 "ipu6_bus_initialize_device isys failed\n");
     651              :         }
     652              : 
     653            1 :         isys_adev->mmu = ipu6_mmu_init(dev, base, ISYS_MMID,
     654              :                                        &ipdata->hw_variant);
     655            1 :         if (IS_ERR(isys_adev->mmu)) {
     656            0 :                 put_device(&isys_adev->auxdev.dev);
     657            0 :                 kfree(pdata);
     658            0 :                 return dev_err_cast_probe(dev, isys_adev->mmu,
     659              :                                 "ipu6_mmu_init(isys_adev->mmu) failed\n");
     660              :         }
     661              : 
     662            1 :         isys_adev->mmu->dev = &isys_adev->auxdev.dev;
     663              : 
     664            1 :         ret = ipu6_bus_add_device(isys_adev);
     665            1 :         if (ret) {
     666            0 :                 kfree(pdata);
     667            0 :                 return ERR_PTR(ret);
     668              :         }
     669              : 
     670              :         return isys_adev;
     671              : }
     672              : 
     673              : static struct ipu6_bus_device *
     674            1 : ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
     675              :                const struct ipu6_buttress_ctrl *ctrl, void __iomem *base,
     676              :                const struct ipu6_psys_internal_pdata *ipdata)
     677              : {
     678              :         struct ipu6_bus_device *psys_adev;
     679              :         struct ipu6_psys_pdata *pdata;
     680              :         int ret;
     681              : 
     682            1 :         pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
     683            1 :         if (!pdata)
     684              :                 return ERR_PTR(-ENOMEM);
     685              : 
     686            1 :         pdata->base = base;
     687            1 :         pdata->ipdata = ipdata;
     688              : 
     689            1 :         psys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, ctrl,
     690              :                                                IPU6_PSYS_NAME);
     691            1 :         if (IS_ERR(psys_adev)) {
     692            0 :                 kfree(pdata);
     693            0 :                 return dev_err_cast_probe(&pdev->dev, psys_adev,
     694              :                                 "ipu6_bus_initialize_device psys failed\n");
     695              :         }
     696              : 
     697            1 :         psys_adev->mmu = ipu6_mmu_init(&pdev->dev, base, PSYS_MMID,
     698              :                                        &ipdata->hw_variant);
     699            1 :         if (IS_ERR(psys_adev->mmu)) {
     700            0 :                 put_device(&psys_adev->auxdev.dev);
     701            0 :                 kfree(pdata);
     702            0 :                 return dev_err_cast_probe(&pdev->dev, psys_adev->mmu,
     703              :                                 "ipu6_mmu_init(psys_adev->mmu) failed\n");
     704              :         }
     705              : 
     706            1 :         psys_adev->mmu->dev = &psys_adev->auxdev.dev;
     707              : 
     708            1 :         ret = ipu6_bus_add_device(psys_adev);
     709            1 :         if (ret) {
     710            0 :                 kfree(pdata);
     711            0 :                 return ERR_PTR(ret);
     712              :         }
     713              : 
     714              :         return psys_adev;
     715              : }
     716              : 
     717            1 : static int ipu6_pci_config_setup(struct pci_dev *dev, u8 hw_ver)
     718              : {
     719              :         int ret;
     720              : 
     721              :         /* No PCI msi capability for IPU6EP */
     722            1 :         if (is_ipu6ep(hw_ver) || is_ipu6ep_mtl(hw_ver)) {
     723              :                 /* likely do nothing as msi not enabled by default */
     724            0 :                 pci_disable_msi(dev);
     725            0 :                 return 0;
     726              :         }
     727              : 
     728            1 :         ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_MSI);
     729            1 :         if (ret < 0)
     730            0 :                 return dev_err_probe(&dev->dev, ret, "Request msi failed");
     731              : 
     732              :         return 0;
     733              : }
     734              : 
     735              : static void ipu6_configure_vc_mechanism(struct ipu6_device *isp)
     736              : {
     737            4 :         u32 val = readl(isp->base + BUTTRESS_REG_BTRS_CTRL);
     738              : 
     739              :         if (IPU6_BTRS_ARB_STALL_MODE_VC0 == IPU6_BTRS_ARB_MODE_TYPE_STALL)
     740              :                 val |= BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC0;
     741              :         else
     742              :                 val &= ~BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC0;
     743              : 
     744              :         if (IPU6_BTRS_ARB_STALL_MODE_VC1 == IPU6_BTRS_ARB_MODE_TYPE_STALL)
     745              :                 val |= BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC1;
     746              :         else
     747            4 :                 val &= ~BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC1;
     748              : 
     749            4 :         writel(val, isp->base + BUTTRESS_REG_BTRS_CTRL);
     750              : }
     751              : 
     752            1 : static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
     753              : {
     754              :         const struct ipu6_buttress_ctrl *isys_ctrl = NULL, *psys_ctrl = NULL;
     755            1 :         struct device *dev = &pdev->dev;
     756              :         void __iomem *isys_base = NULL;
     757              :         void __iomem *psys_base = NULL;
     758              :         struct ipu6_device *isp;
     759            1 :         phys_addr_t phys;
     760              :         int ret;
     761              : 
     762              :         isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
     763            1 :         if (!isp)
     764              :                 return -ENOMEM;
     765              : 
     766            1 :         isp->pdev = pdev;
     767            1 :         INIT_LIST_HEAD(&isp->devices);
     768              : 
     769            1 :         ret = pcim_enable_device(pdev);
     770            1 :         if (ret)
     771            0 :                 return dev_err_probe(dev, ret, "Enable PCI device failed\n");
     772              : 
     773            1 :         phys = pci_resource_start(pdev, IPU6_PCI_BAR);
     774            1 :         dev_dbg(dev, "IPU6 PCI bar[%u] = %pa\n", IPU6_PCI_BAR, &phys);
     775              : 
     776            1 :         isp->base = pcim_iomap_region(pdev, IPU6_PCI_BAR, IPU6_NAME);
     777            1 :         if (IS_ERR(isp->base))
     778            0 :                 return dev_err_probe(dev, PTR_ERR(isp->base),
     779              :                                      "Failed to I/O mem remapping\n");
     780              : 
     781              :         pci_set_drvdata(pdev, isp);
     782            1 :         pci_set_master(pdev);
     783              : 
     784            1 :         isp->cpd_metadata_cmpnt_size = sizeof(struct ipu6_cpd_metadata_cmpnt);
     785            1 :         switch (id->device) {
     786            0 :         case PCI_DEVICE_ID_INTEL_IPU6:
     787            0 :                 isp->hw_ver = IPU6_VER_6;
     788            0 :                 isp->cpd_fw_name = IPU6_FIRMWARE_NAME;
     789            0 :                 isp->buttress.reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
     790            0 :                 break;
     791            0 :         case PCI_DEVICE_ID_INTEL_IPU6SE:
     792            0 :                 isp->hw_ver = IPU6_VER_6SE;
     793            0 :                 isp->cpd_fw_name = IPU6SE_FIRMWARE_NAME;
     794            0 :                 isp->cpd_metadata_cmpnt_size =
     795              :                         sizeof(struct ipu6se_cpd_metadata_cmpnt);
     796            0 :                 isp->buttress.reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
     797            0 :                 break;
     798            0 :         case PCI_DEVICE_ID_INTEL_IPU6EP_ADLP:
     799              :         case PCI_DEVICE_ID_INTEL_IPU6EP_RPLP:
     800            0 :                 isp->hw_ver = IPU6_VER_6EP;
     801            0 :                 isp->cpd_fw_name = IPU6EP_FIRMWARE_NAME;
     802            0 :                 isp->buttress.reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
     803            0 :                 break;
     804            0 :         case PCI_DEVICE_ID_INTEL_IPU6EP_ADLN:
     805            0 :                 isp->hw_ver = IPU6_VER_6EP;
     806            0 :                 isp->cpd_fw_name = IPU6EPADLN_FIRMWARE_NAME;
     807            0 :                 isp->buttress.reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
     808            0 :                 break;
     809            0 :         case PCI_DEVICE_ID_INTEL_IPU6EP_MTL:
     810            0 :                 isp->hw_ver = IPU6_VER_6EP_MTL;
     811            0 :                 isp->cpd_fw_name = IPU6EPMTL_FIRMWARE_NAME;
     812            0 :                 isp->buttress.reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
     813            0 :                 break;
     814            1 :         case PCI_DEVICE_ID_INTEL_IPU4:
     815            1 :                 isp->hw_ver = IPU4_VER_4;
     816            1 :                 isp->cpd_fw_name = IPU4_FIRMWARE_NAME;
     817              :                 // IPU4 uses same cpd metadata cmpnt as ipu6se
     818              :                 // (smaller hash size)
     819            1 :                 isp->cpd_metadata_cmpnt_size =
     820              :                         sizeof(struct ipu6se_cpd_metadata_cmpnt);
     821            1 :                 isp->buttress.reg_irq_sts = BUTTRESS_REG_ISR_ENABLED_STATUS;
     822            1 :                 break;
     823            0 :         default:
     824            0 :                 return dev_err_probe(dev, -ENODEV,
     825              :                                      "Unsupported IPU6 device %x\n",
     826              :                                      id->device);
     827              :         }
     828              : 
     829              :         ipu6_internal_pdata_init(isp);
     830              : 
     831            1 :         isys_base = isp->base + isys_ipdata.hw_variant.offset;
     832            1 :         psys_base = isp->base + psys_ipdata.hw_variant.offset;
     833              : 
     834            1 :         ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(39));
     835            1 :         if (ret)
     836            0 :                 return dev_err_probe(&pdev->dev, ret,
     837              :                                      "Failed to set DMA mask\n");
     838              : 
     839            1 :         dma_set_max_seg_size(dev, UINT_MAX);
     840              : 
     841            1 :         ret = ipu6_pci_config_setup(pdev, isp->hw_ver);
     842            1 :         if (ret)
     843              :                 return ret;
     844              : 
     845            1 :         ret = ipu6_buttress_init(isp);
     846            1 :         if (ret)
     847              :                 return ret;
     848              : 
     849            1 :         ret = request_firmware(&isp->cpd_fw, isp->cpd_fw_name, dev);
     850            1 :         if (ret) {
     851            0 :                 dev_err_probe(&isp->pdev->dev, ret,
     852              :                               "Requesting signed firmware %s failed\n",
     853              :                               isp->cpd_fw_name);
     854            0 :                 goto buttress_exit;
     855              :         }
     856              : 
     857            1 :         ret = ipu6_cpd_validate_cpd_file(isp, isp->cpd_fw->data,
     858            1 :                                          isp->cpd_fw->size);
     859            1 :         if (ret) {
     860            0 :                 dev_err_probe(&isp->pdev->dev, ret,
     861              :                               "Failed to validate cpd\n");
     862            0 :                 goto out_ipu6_bus_del_devices;
     863              :         }
     864              : 
     865            1 :         isys_ctrl = is_ipu4(isp->hw_ver) ?
     866            1 :                         &ipu4_isys_buttress_ctrl : &ipu6_isys_buttress_ctrl;
     867            1 :         isp->isys = ipu6_isys_init(pdev, &pdev->dev, isys_ctrl, isys_base,
     868              :                                    &isys_ipdata);
     869            1 :         if (IS_ERR(isp->isys)) {
     870            0 :                 ret = PTR_ERR(isp->isys);
     871            0 :                 goto out_ipu6_bus_del_devices;
     872              :         }
     873              : 
     874            1 :         psys_ctrl = is_ipu4(isp->hw_ver) ?
     875            1 :                         &ipu4_psys_buttress_ctrl : &ipu6_psys_buttress_ctrl;
     876              : 
     877            1 :         isp->psys = ipu6_psys_init(pdev, &isp->isys->auxdev.dev, psys_ctrl,
     878              :                                    psys_base, &psys_ipdata);
     879            1 :         if (IS_ERR(isp->psys)) {
     880            0 :                 ret = PTR_ERR(isp->psys);
     881            0 :                 goto out_ipu_bridge_uninit;
     882              :         }
     883              : 
     884            1 :         ret = pm_runtime_resume_and_get(&isp->psys->auxdev.dev);
     885            1 :         if (ret < 0)
     886            0 :                 goto out_ipu_bridge_uninit;
     887              : 
     888            1 :         ret = ipu6_mmu_hw_init(isp->psys->mmu);
     889            1 :         if (ret) {
     890            0 :                 dev_err_probe(&isp->pdev->dev, ret,
     891              :                               "Failed to set MMU hardware\n");
     892            0 :                 goto out_ipu_bridge_uninit;
     893              :         }
     894              : 
     895            1 :         ret = ipu6_buttress_map_fw_image(isp->psys, isp->cpd_fw,
     896            1 :                                          &isp->psys->fw_sgt);
     897            1 :         if (ret) {
     898            0 :                 dev_err_probe(&isp->pdev->dev, ret, "failed to map fw image\n");
     899            0 :                 goto out_ipu_bridge_uninit;
     900              :         }
     901              : 
     902            1 :         ret = ipu6_cpd_create_pkg_dir(isp->psys, isp->cpd_fw->data);
     903            1 :         if (ret) {
     904            0 :                 dev_err_probe(&isp->pdev->dev, ret,
     905              :                               "failed to create pkg dir\n");
     906            0 :                 goto out_ipu_bridge_uninit;
     907              :         }
     908              : 
     909            1 :         ret = devm_request_threaded_irq(&pdev->dev, pdev->irq,
     910              :                                         ipu6_buttress_isr,
     911              :                                         ipu6_buttress_isr_threaded,
     912              :                                         IRQF_SHARED, IPU4_NAME, isp);
     913            1 :         if (ret) {
     914            0 :                 dev_err_probe(&pdev->dev, ret, "Requesting irq failed\n");
     915            0 :                 goto out_ipu_bridge_uninit;
     916              :         }
     917              : 
     918            1 :         ret = ipu6_buttress_authenticate(isp);
     919            1 :         if (ret) {
     920            0 :                 dev_err_probe(&isp->pdev->dev, ret,
     921              :                               "FW authentication failed\n");
     922            0 :                 goto out_free_irq;
     923              :         }
     924              : 
     925            1 :         ipu6_mmu_hw_cleanup(isp->psys->mmu);
     926            1 :         pm_runtime_put(&isp->psys->auxdev.dev);
     927              : 
     928              :         /* Configure the arbitration mechanisms for VC requests */
     929              :         ipu6_configure_vc_mechanism(isp);
     930              : 
     931              : #ifdef IPU6
     932              :         val = readl(isp->base + BUTTRESS_REG_SKU);
     933              :         sku_id = FIELD_GET(GENMASK(6, 4), val);
     934              :         version = FIELD_GET(GENMASK(3, 0), val);
     935              :         dev_info(dev, "IPU%u-v%u[%x] hardware version %d\n", version, sku_id,
     936              :                  pdev->device, isp->hw_ver);
     937              : #else
     938              :         // NB: Don't change, currently used as done signal in test
     939            1 :         dev_info(&pdev->dev, "IPU4 PCI driver ready\n");
     940              : #endif
     941              : 
     942            1 :         pm_runtime_put_noidle(dev);
     943            1 :         pm_runtime_allow(dev);
     944              : 
     945            1 :         isp->bus_ready_to_probe = true;
     946              : 
     947            1 :         return 0;
     948              : 
     949              : out_free_irq:
     950            0 :         devm_free_irq(dev, pdev->irq, isp);
     951            0 : out_ipu_bridge_uninit:
     952              : #if IS_ENABLED(CONFIG_VIDEO_IPU4_VIRT_SENSOR)
     953            0 :         ipu4_virt_sensor_remove(pdev);
     954              : #else
     955              :         ambu_ipu_bridge_uninit(&pdev->dev);
     956              : #endif
     957            0 : out_ipu6_bus_del_devices:
     958            0 :         if (isp->psys) {
     959            0 :                 ipu6_cpd_free_pkg_dir(isp->psys);
     960            0 :                 ipu6_buttress_unmap_fw_image(isp->psys, &isp->psys->fw_sgt);
     961              :         }
     962            0 :         if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu))
     963            0 :                 ipu6_mmu_cleanup(isp->psys->mmu);
     964            0 :         if (!IS_ERR_OR_NULL(isp->isys) && !IS_ERR_OR_NULL(isp->isys->mmu))
     965            0 :                 ipu6_mmu_cleanup(isp->isys->mmu);
     966            0 :         ipu6_bus_del_devices(pdev);
     967            0 :         release_firmware(isp->cpd_fw);
     968            0 : buttress_exit:
     969            0 :         ipu6_buttress_exit(isp);
     970              : 
     971            0 :         return ret;
     972              : }
     973              : 
     974            0 : static void ipu6_pci_remove(struct pci_dev *pdev)
     975              : {
     976              :         struct ipu6_device *isp = pci_get_drvdata(pdev);
     977            0 :         struct ipu6_mmu *isys_mmu = isp->isys->mmu;
     978            0 :         struct ipu6_mmu *psys_mmu = isp->psys->mmu;
     979              : 
     980            0 :         devm_free_irq(&pdev->dev, pdev->irq, isp);
     981            0 :         ipu6_cpd_free_pkg_dir(isp->psys);
     982              : 
     983            0 :         ipu6_buttress_unmap_fw_image(isp->psys, &isp->psys->fw_sgt);
     984              : 
     985            0 :         ipu6_buttress_exit(isp);
     986              : 
     987            0 :         ipu6_bus_del_devices(pdev);
     988              : 
     989            0 :         pm_runtime_forbid(&pdev->dev);
     990              :         pm_runtime_get_noresume(&pdev->dev);
     991              : 
     992            0 :         release_firmware(isp->cpd_fw);
     993              : 
     994            0 :         ipu6_mmu_cleanup(psys_mmu);
     995            0 :         ipu6_mmu_cleanup(isys_mmu);
     996              : 
     997              : #if IS_ENABLED(CONFIG_VIDEO_IPU4_VIRT_SENSOR)
     998            0 :         ipu4_virt_sensor_remove(pdev);
     999              : #else
    1000              :         ambu_ipu_bridge_uninit(&pdev->dev);
    1001              : #endif
    1002            0 : }
    1003              : 
    1004            0 : static void ipu6_pci_reset_prepare(struct pci_dev *pdev)
    1005              : {
    1006              :         struct ipu6_device *isp = pci_get_drvdata(pdev);
    1007              : 
    1008            0 :         pm_runtime_forbid(&isp->pdev->dev);
    1009            0 : }
    1010              : 
    1011            0 : static void ipu6_pci_reset_done(struct pci_dev *pdev)
    1012              : {
    1013              :         struct ipu6_device *isp = pci_get_drvdata(pdev);
    1014              : 
    1015            0 :         ipu6_buttress_restore(isp);
    1016            0 :         if (isp->secure_mode)
    1017            0 :                 ipu6_buttress_reset_authentication(isp);
    1018              : 
    1019            0 :         isp->need_ipc_reset = true;
    1020            0 :         pm_runtime_allow(&isp->pdev->dev);
    1021            0 : }
    1022              : 
    1023              : /*
    1024              :  * PCI base driver code requires driver to provide these to enable
    1025              :  * PCI device level PM state transitions (D0<->D3)
    1026              :  */
    1027            4 : static int ipu6_suspend(struct device *dev)
    1028              : {
    1029              :         struct pci_dev *pdev = to_pci_dev(dev);
    1030              : 
    1031            4 :         synchronize_irq(pdev->irq);
    1032            4 :         return 0;
    1033              : }
    1034              : 
    1035              : static int ipu6_resume(struct device *dev)
    1036              : {
    1037              :         struct pci_dev *pdev = to_pci_dev(dev);
    1038              :         struct ipu6_device *isp = pci_get_drvdata(pdev);
    1039              :         struct ipu6_buttress *b = &isp->buttress;
    1040              :         int ret;
    1041              : 
    1042              :         /* Configure the arbitration mechanisms for VC requests */
    1043              :         ipu6_configure_vc_mechanism(isp);
    1044              : 
    1045              :         isp->secure_mode = ipu6_buttress_get_secure_mode(isp);
    1046              :         dev_info(dev, "IPU6 in %s mode\n",
    1047              :                  isp->secure_mode ? "secure" : "non-secure");
    1048              : 
    1049              :         ipu6_buttress_restore(isp);
    1050              : 
    1051              :         ret = ipu6_buttress_ipc_reset(isp, &b->cse);
    1052              :         if (ret)
    1053              :                 dev_err(&isp->pdev->dev, "IPC reset protocol failed!\n");
    1054              : 
    1055              :         ret = pm_runtime_resume_and_get(&isp->psys->auxdev.dev);
    1056              :         if (ret < 0) {
    1057              :                 dev_err(&isp->psys->auxdev.dev, "Failed to get runtime PM\n");
    1058              :                 return 0;
    1059              :         }
    1060              : 
    1061              :         ret = ipu6_buttress_authenticate(isp);
    1062              :         if (ret)
    1063              :                 dev_err(&isp->pdev->dev, "FW authentication failed(%d)\n", ret);
    1064              : 
    1065              :         pm_runtime_put(&isp->psys->auxdev.dev);
    1066              : 
    1067              :         return 0;
    1068              : }
    1069              : 
    1070            3 : static int ipu6_runtime_resume(struct device *dev)
    1071              : {
    1072              :         struct pci_dev *pdev = to_pci_dev(dev);
    1073              :         struct ipu6_device *isp = pci_get_drvdata(pdev);
    1074              :         int ret;
    1075              : 
    1076              :         ipu6_configure_vc_mechanism(isp);
    1077            3 :         ipu6_buttress_restore(isp);
    1078              : 
    1079            3 :         if (isp->need_ipc_reset) {
    1080              :                 struct ipu6_buttress *b = &isp->buttress;
    1081              : 
    1082            0 :                 isp->need_ipc_reset = false;
    1083            0 :                 ret = ipu6_buttress_ipc_reset(isp, &b->cse);
    1084            0 :                 if (ret)
    1085            0 :                         dev_err(&isp->pdev->dev, "IPC reset protocol failed\n");
    1086              :         }
    1087              : 
    1088            3 :         return 0;
    1089              : }
    1090              : 
    1091              : static const struct dev_pm_ops ipu6_pm_ops = {
    1092              :         SYSTEM_SLEEP_PM_OPS(&ipu6_suspend, &ipu6_resume)
    1093              :         RUNTIME_PM_OPS(&ipu6_suspend, &ipu6_runtime_resume, NULL)
    1094              : };
    1095              : 
    1096              : static const struct pci_device_id ipu6_pci_tbl[] = {
    1097              :         { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU4)},
    1098              :         { }
    1099              : };
    1100              : MODULE_DEVICE_TABLE(pci, ipu6_pci_tbl);
    1101              : 
    1102              : static const struct pci_error_handlers pci_err_handlers = {
    1103              :         .reset_prepare = ipu6_pci_reset_prepare,
    1104              :         .reset_done = ipu6_pci_reset_done,
    1105              : };
    1106              : 
    1107              : static struct pci_driver ipu6_pci_driver = {
    1108              :         .name = IPU4_NAME,
    1109              :         .id_table = ipu6_pci_tbl,
    1110              :         .probe = ipu6_pci_probe,
    1111              :         .remove = ipu6_pci_remove,
    1112              :         .driver = {
    1113              :                 .pm = pm_ptr(&ipu6_pm_ops),
    1114              :         },
    1115              :         .err_handler = &pci_err_handlers,
    1116              : };
    1117              : 
    1118            1 : module_pci_driver(ipu6_pci_driver);
    1119              : 
    1120              : MODULE_IMPORT_NS(INTEL_IPU_BRIDGE);
    1121              : MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
    1122              : MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
    1123              : MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
    1124              : MODULE_AUTHOR("Qingwu Zhang <qingwu.zhang@intel.com>");
    1125              : MODULE_AUTHOR("Yunliang Ding <yunliang.ding@intel.com>");
    1126              : MODULE_AUTHOR("Hongju Wang <hongju.wang@intel.com>");
    1127              : MODULE_LICENSE("GPL");
    1128              : MODULE_DESCRIPTION("Intel IPU4 PCI driver");
        

Generated by: LCOV version 2.0-1