787 changes: 787 additions & 0 deletions drivers/media/pci/intel/ipu-mmu.c

Large diffs are not rendered by default.

67 changes: 67 additions & 0 deletions drivers/media/pci/intel/ipu-mmu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2013 - 2020 Intel Corporation */

#ifndef IPU_MMU_H
#define IPU_MMU_H

#include <linux/dma-mapping.h>

#include "ipu.h"
#include "ipu-pdata.h"

#define ISYS_MMID 1
#define PSYS_MMID 0

/*
* @pgtbl: virtual address of the l1 page table (one page)
*/
struct ipu_mmu_info {
u32 __iomem *pgtbl;
dma_addr_t aperture_start;
dma_addr_t aperture_end;
unsigned long pgsize_bitmap;

spinlock_t lock; /* Serialize access to users */
struct ipu_dma_mapping *dmap;
u32 dummy_l2_tbl;
u32 dummy_page;
};

/*
* @pgtbl: physical address of the l1 page table
*/
struct ipu_mmu {
struct list_head node;

struct ipu_mmu_hw *mmu_hw;
unsigned int nr_mmus;
int mmid;

phys_addr_t pgtbl;
struct device *dev;

struct ipu_dma_mapping *dmap;
struct list_head vma_list;

struct page *trash_page;
dma_addr_t iova_addr_trash;

bool ready;
spinlock_t ready_lock; /* Serialize access to bool ready */

void (*tlb_invalidate)(struct ipu_mmu *mmu);
};

struct ipu_mmu *ipu_mmu_init(struct device *dev,
void __iomem *base, int mmid,
const struct ipu_hw_variants *hw);
void ipu_mmu_cleanup(struct ipu_mmu *mmu);
int ipu_mmu_hw_init(struct ipu_mmu *mmu);
int ipu_mmu_hw_cleanup(struct ipu_mmu *mmu);
int ipu_mmu_map(struct ipu_mmu_info *mmu_info, unsigned long iova,
phys_addr_t paddr, size_t size);
size_t ipu_mmu_unmap(struct ipu_mmu_info *mmu_info, unsigned long iova,
size_t size);
phys_addr_t ipu_mmu_iova_to_phys(struct ipu_mmu_info *mmu_info,
dma_addr_t iova);
#endif
251 changes: 251 additions & 0 deletions drivers/media/pci/intel/ipu-pdata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2013 - 2020 Intel Corporation */

#ifndef IPU_PDATA_H
#define IPU_PDATA_H

#define IPU_MMU_NAME IPU_NAME "-mmu"
#define IPU_ISYS_CSI2_NAME IPU_NAME "-csi2"
#define IPU_ISYS_NAME IPU_NAME "-isys"
#define IPU_PSYS_NAME IPU_NAME "-psys"
#define IPU_BUTTRESS_NAME IPU_NAME "-buttress"

#define IPU_MMU_MAX_DEVICES 4
#define IPU_MMU_ADDRESS_BITS 32
/* The firmware is accessible within the first 2 GiB only in non-secure mode. */
#define IPU_MMU_ADDRESS_BITS_NON_SECURE 31

#define IPU_MMU_MAX_TLB_L1_STREAMS 32
#define IPU_MMU_MAX_TLB_L2_STREAMS 32
#define IPU_MAX_LI_BLOCK_ADDR 128
#define IPU_MAX_L2_BLOCK_ADDR 64

#define IPU_ISYS_MAX_CSI2_LEGACY_PORTS 4
#define IPU_ISYS_MAX_CSI2_COMBO_PORTS 2

#define IPU_MAX_FRAME_COUNTER 0xff

/*
* To maximize the IOSF utlization, IPU need to send requests in bursts.
* At the DMA interface with the buttress, there are CDC FIFOs with burst
* collection capability. CDC FIFO burst collectors have a configurable
* threshold and is configured based on the outcome of performance measurements.
*
* isys has 3 ports with IOSF interface for VC0, VC1 and VC2
* psys has 4 ports with IOSF interface for VC0, VC1w, VC1r and VC2
*
* Threshold values are pre-defined and are arrived at after performance
* evaluations on a type of IPU4
*/
#define IPU_MAX_VC_IOSF_PORTS 4

/*
* IPU must configure correct arbitration mechanism related to the IOSF VC
* requests. There are two options per VC0 and VC1 - > 0 means rearbitrate on
* stall and 1 means stall until the request is completed.
*/
#define IPU_BTRS_ARB_MODE_TYPE_REARB 0
#define IPU_BTRS_ARB_MODE_TYPE_STALL 1

/* Currently chosen arbitration mechanism for VC0 */
#define IPU_BTRS_ARB_STALL_MODE_VC0 \
IPU_BTRS_ARB_MODE_TYPE_REARB

/* Currently chosen arbitration mechanism for VC1 */
#define IPU_BTRS_ARB_STALL_MODE_VC1 \
IPU_BTRS_ARB_MODE_TYPE_REARB

struct ipu_isys_subdev_pdata;

/*
* MMU Invalidation HW bug workaround by ZLW mechanism
*
* IPU4 MMUV2 has a bug in the invalidation mechanism which might result in
* wrong translation or replication of the translation. This will cause data
* corruption. So we cannot directly use the MMU V2 invalidation registers
* to invalidate the MMU. Instead, whenever an invalidate is called, we need to
* clear the TLB by evicting all the valid translations by filling it with trash
* buffer (which is guaranteed not to be used by any other processes). ZLW is
* used to fill the L1 and L2 caches with the trash buffer translations. ZLW
* or Zero length write, is pre-fetch mechanism to pre-fetch the pages in
* advance to the L1 and L2 caches without triggering any memory operations.
*
* In MMU V2, L1 -> 16 streams and 64 blocks, maximum 16 blocks per stream
* One L1 block has 16 entries, hence points to 16 * 4K pages
* L2 -> 16 streams and 32 blocks. 2 blocks per streams
* One L2 block maps to 1024 L1 entries, hence points to 4MB address range
* 2 blocks per L2 stream means, 1 stream points to 8MB range
*
* As we need to clear the caches and 8MB being the biggest cache size, we need
* to have trash buffer which points to 8MB address range. As these trash
* buffers are not used for any memory transactions, we need only the least
* amount of physical memory. So we reserve 8MB IOVA address range but only
* one page is reserved from physical memory. Each of this 8MB IOVA address
* range is then mapped to the same physical memory page.
*/
/* One L2 entry maps 1024 L1 entries and one L1 entry per page */
#define IPU_MMUV2_L2_RANGE (1024 * PAGE_SIZE)
/* Max L2 blocks per stream */
#define IPU_MMUV2_MAX_L2_BLOCKS 2
/* Max L1 blocks per stream */
#define IPU_MMUV2_MAX_L1_BLOCKS 16
#define IPU_MMUV2_TRASH_RANGE (IPU_MMUV2_L2_RANGE * \
IPU_MMUV2_MAX_L2_BLOCKS)
/* Entries per L1 block */
#define MMUV2_ENTRIES_PER_L1_BLOCK 16
#define MMUV2_TRASH_L1_BLOCK_OFFSET (MMUV2_ENTRIES_PER_L1_BLOCK * \
PAGE_SIZE)
#define MMUV2_TRASH_L2_BLOCK_OFFSET IPU_MMUV2_L2_RANGE

/*
* In some of the IPU4 MMUs, there is provision to configure L1 and L2 page
* table caches. Both these L1 and L2 caches are divided into multiple sections
* called streams. There is maximum 16 streams for both caches. Each of these
* sections are subdivided into multiple blocks. When nr_l1streams = 0 and
* nr_l2streams = 0, means the MMU is of type MMU_V1 and do not support
* L1/L2 page table caches.
*
* L1 stream per block sizes are configurable and varies per usecase.
* L2 has constant block sizes - 2 blocks per stream.
*
* MMU1 support pre-fetching of the pages to have less cache lookup misses. To
* enable the pre-fetching, MMU1 AT (Address Translator) device registers
* need to be configured.
*
* There are four types of memory accesses which requires ZLW configuration.
* ZLW(Zero Length Write) is a mechanism to enable VT-d pre-fetching on IOMMU.
*
* 1. Sequential Access or 1D mode
* Set ZLW_EN -> 1
* set ZLW_PAGE_CROSS_1D -> 1
* Set ZLW_N to "N" pages so that ZLW will be inserte N pages ahead where
* N is pre-defined and hardcoded in the platform data
* Set ZLW_2D -> 0
*
* 2. ZLW 2D mode
* Set ZLW_EN -> 1
* set ZLW_PAGE_CROSS_1D -> 1,
* Set ZLW_N -> 0
* Set ZLW_2D -> 1
*
* 3. ZLW Enable (no 1D or 2D mode)
* Set ZLW_EN -> 1
* set ZLW_PAGE_CROSS_1D -> 0,
* Set ZLW_N -> 0
* Set ZLW_2D -> 0
*
* 4. ZLW disable
* Set ZLW_EN -> 0
* set ZLW_PAGE_CROSS_1D -> 0,
* Set ZLW_N -> 0
* Set ZLW_2D -> 0
*
* To configure the ZLW for the above memory access, four registers are
* available. Hence to track these four settings, we have the following entries
* in the struct ipu_mmu_hw. Each of these entries are per stream and
* available only for the L1 streams.
*
* a. l1_zlw_en -> To track zlw enabled per stream (ZLW_EN)
* b. l1_zlw_1d_mode -> Track 1D mode per stream. ZLW inserted at page boundary
* c. l1_ins_zlw_ahead_pages -> to track how advance the ZLW need to be inserted
* Insert ZLW request N pages ahead address.
* d. l1_zlw_2d_mode -> To track 2D mode per stream (ZLW_2D)
*
*
* Currently L1/L2 streams, blocks, AT ZLW configurations etc. are pre-defined
* as per the usecase specific calculations. Any change to this pre-defined
* table has to happen in sync with IPU4 FW.
*/
struct ipu_mmu_hw {
union {
unsigned long offset;
void __iomem *base;
};
unsigned int info_bits;
u8 nr_l1streams;
/*
* L1 has variable blocks per stream - total of 64 blocks and maximum of
* 16 blocks per stream. Configurable by using the block start address
* per stream. Block start address is calculated from the block size
*/
u8 l1_block_sz[IPU_MMU_MAX_TLB_L1_STREAMS];
/* Is ZLW is enabled in each stream */
bool l1_zlw_en[IPU_MMU_MAX_TLB_L1_STREAMS];
bool l1_zlw_1d_mode[IPU_MMU_MAX_TLB_L1_STREAMS];
u8 l1_ins_zlw_ahead_pages[IPU_MMU_MAX_TLB_L1_STREAMS];
bool l1_zlw_2d_mode[IPU_MMU_MAX_TLB_L1_STREAMS];

u32 l1_stream_id_reg_offset;
u32 l2_stream_id_reg_offset;

u8 nr_l2streams;
/*
* L2 has fixed 2 blocks per stream. Block address is calculated
* from the block size
*/
u8 l2_block_sz[IPU_MMU_MAX_TLB_L2_STREAMS];
/* flag to track if WA is needed for successive invalidate HW bug */
bool insert_read_before_invalidate;
/* flag to track if zlw based mmu invalidation is needed */
bool zlw_invalidate;
};

struct ipu_mmu_pdata {
unsigned int nr_mmus;
struct ipu_mmu_hw mmu_hw[IPU_MMU_MAX_DEVICES];
int mmid;
};

struct ipu_isys_csi2_pdata {
void __iomem *base;
};

#define IPU_EV_AUTO 0xff

struct ipu_isys_internal_csi2_pdata {
unsigned int nports;
unsigned int *offsets;
};

struct ipu_isys_internal_tpg_pdata {
unsigned int ntpgs;
unsigned int *offsets;
unsigned int *sels;
};

/*
* One place to handle all the IPU HW variations
*/
struct ipu_hw_variants {
unsigned long offset;
unsigned int nr_mmus;
struct ipu_mmu_hw mmu_hw[IPU_MMU_MAX_DEVICES];
u8 cdc_fifos;
u8 cdc_fifo_threshold[IPU_MAX_VC_IOSF_PORTS];
u32 dmem_offset;
u32 spc_offset; /* SPC offset from psys base */
};

struct ipu_isys_internal_pdata {
struct ipu_isys_internal_csi2_pdata csi2;
struct ipu_isys_internal_tpg_pdata tpg;
struct ipu_hw_variants hw_variant;
u32 num_parallel_streams;
u32 isys_dma_overshoot;
};

struct ipu_isys_pdata {
void __iomem *base;
const struct ipu_isys_internal_pdata *ipdata;
};

struct ipu_psys_internal_pdata {
struct ipu_hw_variants hw_variant;
};

struct ipu_psys_pdata {
void __iomem *base;
const struct ipu_psys_internal_pdata *ipdata;
};

#endif
227 changes: 227 additions & 0 deletions drivers/media/pci/intel/ipu-psys-compat32.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2013 - 2020 Intel Corporation

#include <linux/compat.h>
#include <linux/errno.h>
#include <linux/uaccess.h>

#include <uapi/linux/ipu-psys.h>

#include "ipu-psys.h"

static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret = -ENOTTY;

if (file->f_op->unlocked_ioctl)
ret = file->f_op->unlocked_ioctl(file, cmd, arg);

return ret;
}

struct ipu_psys_buffer32 {
u64 len;
union {
int fd;
compat_uptr_t userptr;
u64 reserved;
} base;
u32 data_offset;
u32 bytes_used;
u32 flags;
u32 reserved[2];
} __packed;

struct ipu_psys_command32 {
u64 issue_id;
u64 user_token;
u32 priority;
compat_uptr_t pg_manifest;
compat_uptr_t buffers;
int pg;
u32 pg_manifest_size;
u32 bufcount;
u32 min_psys_freq;
u32 frame_counter;
u32 reserved[2];
} __packed;

struct ipu_psys_manifest32 {
u32 index;
u32 size;
compat_uptr_t manifest;
u32 reserved[5];
} __packed;

static int
get_ipu_psys_command32(struct ipu_psys_command *kp,
struct ipu_psys_command32 __user *up)
{
compat_uptr_t pgm, bufs;
bool access_ok;

access_ok = access_ok(up, sizeof(struct ipu_psys_command32));
if (!access_ok || get_user(kp->issue_id, &up->issue_id) ||
get_user(kp->user_token, &up->user_token) ||
get_user(kp->priority, &up->priority) ||
get_user(pgm, &up->pg_manifest) ||
get_user(bufs, &up->buffers) ||
get_user(kp->pg, &up->pg) ||
get_user(kp->pg_manifest_size, &up->pg_manifest_size) ||
get_user(kp->bufcount, &up->bufcount) ||
get_user(kp->min_psys_freq, &up->min_psys_freq) ||
get_user(kp->frame_counter, &up->frame_counter)
)
return -EFAULT;

kp->pg_manifest = compat_ptr(pgm);
kp->buffers = compat_ptr(bufs);

return 0;
}

static int
get_ipu_psys_buffer32(struct ipu_psys_buffer *kp,
struct ipu_psys_buffer32 __user *up)
{
compat_uptr_t ptr;
bool access_ok;

access_ok = access_ok(up, sizeof(struct ipu_psys_buffer32));
if (!access_ok || get_user(kp->len, &up->len) ||
get_user(ptr, &up->base.userptr) ||
get_user(kp->data_offset, &up->data_offset) ||
get_user(kp->bytes_used, &up->bytes_used) ||
get_user(kp->flags, &up->flags))
return -EFAULT;

kp->base.userptr = compat_ptr(ptr);

return 0;
}

static int
put_ipu_psys_buffer32(struct ipu_psys_buffer *kp,
struct ipu_psys_buffer32 __user *up)
{
bool access_ok;

access_ok = access_ok(up, sizeof(struct ipu_psys_buffer32));
if (!access_ok || put_user(kp->len, &up->len) ||
put_user(kp->base.fd, &up->base.fd) ||
put_user(kp->data_offset, &up->data_offset) ||
put_user(kp->bytes_used, &up->bytes_used) ||
put_user(kp->flags, &up->flags))
return -EFAULT;

return 0;
}

static int
get_ipu_psys_manifest32(struct ipu_psys_manifest *kp,
struct ipu_psys_manifest32 __user *up)
{
compat_uptr_t ptr;
bool access_ok;

access_ok = access_ok(up, sizeof(struct ipu_psys_manifest32));
if (!access_ok || get_user(kp->index, &up->index) ||
get_user(kp->size, &up->size) || get_user(ptr, &up->manifest))
return -EFAULT;

kp->manifest = compat_ptr(ptr);

return 0;
}

static int
put_ipu_psys_manifest32(struct ipu_psys_manifest *kp,
struct ipu_psys_manifest32 __user *up)
{
compat_uptr_t ptr = (u32)((unsigned long)kp->manifest);
bool access_ok;

access_ok = access_ok(up, sizeof(struct ipu_psys_manifest32));
if (!access_ok || put_user(kp->index, &up->index) ||
put_user(kp->size, &up->size) || put_user(ptr, &up->manifest))
return -EFAULT;

return 0;
}

#define IPU_IOC_GETBUF32 _IOWR('A', 4, struct ipu_psys_buffer32)
#define IPU_IOC_PUTBUF32 _IOWR('A', 5, struct ipu_psys_buffer32)
#define IPU_IOC_QCMD32 _IOWR('A', 6, struct ipu_psys_command32)
#define IPU_IOC_CMD_CANCEL32 _IOWR('A', 8, struct ipu_psys_command32)
#define IPU_IOC_GET_MANIFEST32 _IOWR('A', 9, struct ipu_psys_manifest32)

long ipu_psys_compat_ioctl32(struct file *file, unsigned int cmd,
unsigned long arg)
{
union {
struct ipu_psys_buffer buf;
struct ipu_psys_command cmd;
struct ipu_psys_event ev;
struct ipu_psys_manifest m;
} karg;
int compatible_arg = 1;
int err = 0;
void __user *up = compat_ptr(arg);

switch (cmd) {
case IPU_IOC_GETBUF32:
cmd = IPU_IOC_GETBUF;
break;
case IPU_IOC_PUTBUF32:
cmd = IPU_IOC_PUTBUF;
break;
case IPU_IOC_QCMD32:
cmd = IPU_IOC_QCMD;
break;
case IPU_IOC_GET_MANIFEST32:
cmd = IPU_IOC_GET_MANIFEST;
break;
}

switch (cmd) {
case IPU_IOC_GETBUF:
case IPU_IOC_PUTBUF:
err = get_ipu_psys_buffer32(&karg.buf, up);
compatible_arg = 0;
break;
case IPU_IOC_QCMD:
err = get_ipu_psys_command32(&karg.cmd, up);
compatible_arg = 0;
break;
case IPU_IOC_GET_MANIFEST:
err = get_ipu_psys_manifest32(&karg.m, up);
compatible_arg = 0;
break;
}
if (err)
return err;

if (compatible_arg) {
err = native_ioctl(file, cmd, (unsigned long)up);
} else {
mm_segment_t old_fs = get_fs();

set_fs(KERNEL_DS);
err = native_ioctl(file, cmd, (unsigned long)&karg);
set_fs(old_fs);
}

if (err)
return err;

switch (cmd) {
case IPU_IOC_GETBUF:
err = put_ipu_psys_buffer32(&karg.buf, up);
break;
case IPU_IOC_GET_MANIFEST:
err = put_ipu_psys_manifest32(&karg.m, up);
break;
}
return err;
}
EXPORT_SYMBOL_GPL(ipu_psys_compat_ioctl32);
1,632 changes: 1,632 additions & 0 deletions drivers/media/pci/intel/ipu-psys.c

Large diffs are not rendered by default.

218 changes: 218 additions & 0 deletions drivers/media/pci/intel/ipu-psys.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2013 - 2020 Intel Corporation */

#ifndef IPU_PSYS_H
#define IPU_PSYS_H

#include <linux/cdev.h>
#include <linux/workqueue.h>

#include "ipu.h"
#include "ipu-pdata.h"
#include "ipu-fw-psys.h"
#include "ipu-platform-psys.h"

#define IPU_PSYS_PG_POOL_SIZE 16
#define IPU_PSYS_PG_MAX_SIZE 2048
#define IPU_MAX_PSYS_CMD_BUFFERS 32
#define IPU_PSYS_EVENT_CMD_COMPLETE IPU_FW_PSYS_EVENT_TYPE_SUCCESS
#define IPU_PSYS_EVENT_FRAGMENT_COMPLETE IPU_FW_PSYS_EVENT_TYPE_SUCCESS
#define IPU_PSYS_CLOSE_TIMEOUT_US 50
#define IPU_PSYS_CLOSE_TIMEOUT (100000 / IPU_PSYS_CLOSE_TIMEOUT_US)
#define IPU_PSYS_WORK_QUEUE system_power_efficient_wq
#define IPU_MAX_RESOURCES 128

/* Opaque structure. Do not access fields. */
struct ipu_resource {
u32 id;
int elements; /* Number of elements available to allocation */
unsigned long *bitmap; /* Allocation bitmap, a bit for each element */
};

enum ipu_resource_type {
IPU_RESOURCE_DEV_CHN = 0,
IPU_RESOURCE_EXT_MEM,
IPU_RESOURCE_DFM
};

/* Allocation of resource(s) */
/* Opaque structure. Do not access fields. */
struct ipu_resource_alloc {
enum ipu_resource_type type;
struct ipu_resource *resource;
int elements;
int pos;
};

/*
* This struct represents all of the currently allocated
* resources from IPU model. It is used also for allocating
* resources for the next set of PGs to be run on IPU
* (ie. those PGs which are not yet being run and which don't
* yet reserve real IPU resources).
* Use larger array to cover existing resource quantity
*/

/* resource size may need expand for new resource model */
struct ipu_psys_resource_pool {
u32 cells; /* Bitmask of cells allocated */
struct ipu_resource dev_channels[16];
struct ipu_resource ext_memory[32];
struct ipu_resource dfms[16];
DECLARE_BITMAP(cmd_queues, 32);
};

/*
* This struct keeps book of the resources allocated for a specific PG.
* It is used for freeing up resources from struct ipu_psys_resources
* when the PG is released from IPU4 (or model of IPU4).
*/
struct ipu_psys_resource_alloc {
u32 cells; /* Bitmask of cells needed */
struct ipu_resource_alloc
resource_alloc[IPU_MAX_RESOURCES];
int resources;
};

struct task_struct;
struct ipu_psys {
struct ipu_psys_capability caps;
struct cdev cdev;
struct device dev;

struct mutex mutex; /* Psys various */
int power;
bool icache_prefetch_sp;
bool icache_prefetch_isp;
spinlock_t power_lock; /* Serialize access to power */
spinlock_t pgs_lock; /* Protect pgs list access */
struct list_head fhs;
struct list_head pgs;
struct list_head started_kcmds_list;
struct ipu_psys_pdata *pdata;
struct ipu_bus_device *adev;
struct ia_css_syscom_context *dev_ctx;
struct ia_css_syscom_config *syscom_config;
struct ia_css_psys_server_init *server_init;
struct task_struct *sched_cmd_thread;
struct work_struct watchdog_work;
wait_queue_head_t sched_cmd_wq;
atomic_t wakeup_count; /* Psys schedule thread wakeup count */
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfsdir;
#endif

/* Resources needed to be managed for process groups */
struct ipu_psys_resource_pool resource_pool_running;
struct ipu_psys_resource_pool resource_pool_started;

const struct firmware *fw;
struct sg_table fw_sgt;
u64 *pkg_dir;
dma_addr_t pkg_dir_dma_addr;
unsigned int pkg_dir_size;
unsigned long timeout;

int active_kcmds, started_kcmds;
void *fwcom;

int power_gating;
};

struct ipu_psys_fh {
struct ipu_psys *psys;
struct mutex mutex; /* Protects bufmap & kcmds fields */
struct list_head list;
struct list_head bufmap;
wait_queue_head_t wait;
struct ipu_psys_scheduler sched;
};

struct ipu_psys_pg {
struct ipu_fw_psys_process_group *pg;
size_t size;
size_t pg_size;
dma_addr_t pg_dma_addr;
struct list_head list;
struct ipu_psys_resource_alloc resource_alloc;
};

struct ipu_psys_kcmd {
struct ipu_psys_fh *fh;
struct list_head list;
struct ipu_psys_buffer_set *kbuf_set;
enum ipu_psys_cmd_state state;
void *pg_manifest;
size_t pg_manifest_size;
struct ipu_psys_kbuffer **kbufs;
struct ipu_psys_buffer *buffers;
size_t nbuffers;
struct ipu_fw_psys_process_group *pg_user;
struct ipu_psys_pg *kpg;
u64 user_token;
u64 issue_id;
u32 priority;
u32 kernel_enable_bitmap[4];
u32 terminal_enable_bitmap[4];
u32 routing_enable_bitmap[4];
u32 rbm[5];
struct ipu_buttress_constraint constraint;
struct ipu_psys_event ev;
struct timer_list watchdog;
};

struct ipu_dma_buf_attach {
struct device *dev;
u64 len;
void *userptr;
struct sg_table *sgt;
bool vma_is_io;
struct page **pages;
size_t npages;
};

struct ipu_psys_kbuffer {
u64 len;
void *userptr;
u32 flags;
int fd;
void *kaddr;
struct list_head list;
dma_addr_t dma_addr;
struct sg_table *sgt;
struct dma_buf_attachment *db_attach;
struct dma_buf *dbuf;
bool valid; /* True when buffer is usable */
};

#define inode_to_ipu_psys(inode) \
container_of((inode)->i_cdev, struct ipu_psys, cdev)

#ifdef CONFIG_COMPAT
long ipu_psys_compat_ioctl32(struct file *file, unsigned int cmd,
unsigned long arg);
#endif

void ipu_psys_setup_hw(struct ipu_psys *psys);
void ipu_psys_subdomains_power(struct ipu_psys *psys, bool on);
void ipu_psys_handle_events(struct ipu_psys *psys);
int ipu_psys_kcmd_new(struct ipu_psys_command *cmd, struct ipu_psys_fh *fh);
void ipu_psys_run_next(struct ipu_psys *psys);
void ipu_psys_watchdog_work(struct work_struct *work);
struct ipu_psys_pg *__get_pg_buf(struct ipu_psys *psys, size_t pg_size);
struct ipu_psys_kbuffer *
ipu_psys_lookup_kbuffer(struct ipu_psys_fh *fh, int fd);
int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
struct ipu_psys_kbuffer *kbuf);
struct ipu_psys_kbuffer *
ipu_psys_lookup_kbuffer_by_kaddr(struct ipu_psys_fh *fh, void *kaddr);
#ifdef IPU_PSYS_GPC
int ipu_psys_gpc_init_debugfs(struct ipu_psys *psys);
#endif
int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool *pool);
void ipu_psys_resource_pool_cleanup(struct ipu_psys_resource_pool *pool);
struct ipu_psys_kcmd *ipu_get_completed_kcmd(struct ipu_psys_fh *fh);
long ipu_ioctl_dqevent(struct ipu_psys_event *event,
struct ipu_psys_fh *fh, unsigned int f_flags);

#endif /* IPU_PSYS_H */
880 changes: 880 additions & 0 deletions drivers/media/pci/intel/ipu-trace.c

Large diffs are not rendered by default.

312 changes: 312 additions & 0 deletions drivers/media/pci/intel/ipu-trace.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2014 - 2020 Intel Corporation */

#ifndef IPU_TRACE_H
#define IPU_TRACE_H
#include <linux/debugfs.h>

#define TRACE_REG_MAX_BLOCK_SIZE 0x0fff

#define TRACE_REG_END_MARK 0xffff

#define TRACE_REG_CMD_TYPE_D64 0x0
#define TRACE_REG_CMD_TYPE_D64M 0x1
#define TRACE_REG_CMD_TYPE_D64TS 0x2
#define TRACE_REG_CMD_TYPE_D64MTS 0x3

/* Trace unit register offsets */
#define TRACE_REG_TUN_DDR_ENABLE 0x000
#define TRACE_REG_TUN_NPK_ENABLE 0x004
#define TRACE_REG_TUN_DDR_INFO_VAL 0x008
#define TRACE_REG_TUN_NPK_ADDR 0x00C
#define TRACE_REG_TUN_DRAM_BASE_ADDR 0x010
#define TRACE_REG_TUN_DRAM_END_ADDR 0x014
#define TRACE_REG_TUN_LOCAL_TIMER0 0x018
#define TRACE_REG_TUN_LOCAL_TIMER1 0x01C
#define TRACE_REG_TUN_WR_PTR 0x020
#define TRACE_REG_TUN_RD_PTR 0x024

#define TRACE_REG_CREATE_TUN_REGISTER_LIST { \
TRACE_REG_TUN_DDR_ENABLE, \
TRACE_REG_TUN_NPK_ENABLE, \
TRACE_REG_TUN_DDR_INFO_VAL, \
TRACE_REG_TUN_NPK_ADDR, \
TRACE_REG_END_MARK \
}

/*
* Following registers are left out on purpose:
* TUN_LOCAL_TIMER0, TUN_LOCAL_TIMER1, TUN_DRAM_BASE_ADDR
* TUN_DRAM_END_ADDR, TUN_WR_PTR, TUN_RD_PTR
*/

/* Trace monitor register offsets */
#define TRACE_REG_TM_TRACE_ADDR_A 0x0900
#define TRACE_REG_TM_TRACE_ADDR_B 0x0904
#define TRACE_REG_TM_TRACE_ADDR_C 0x0908
#define TRACE_REG_TM_TRACE_ADDR_D 0x090c
#define TRACE_REG_TM_TRACE_ENABLE_NPK 0x0910
#define TRACE_REG_TM_TRACE_ENABLE_DDR 0x0914
#define TRACE_REG_TM_TRACE_PER_PC 0x0918
#define TRACE_REG_TM_TRACE_PER_BRANCH 0x091c
#define TRACE_REG_TM_TRACE_HEADER 0x0920
#define TRACE_REG_TM_TRACE_CFG 0x0924
#define TRACE_REG_TM_TRACE_LOST_PACKETS 0x0928
#define TRACE_REG_TM_TRACE_LP_CLEAR 0x092c
#define TRACE_REG_TM_TRACE_LMRUN_MASK 0x0930
#define TRACE_REG_TM_TRACE_LMRUN_PC_LOW 0x0934
#define TRACE_REG_TM_TRACE_LMRUN_PC_HIGH 0x0938
#define TRACE_REG_TM_TRACE_MMIO_SEL 0x093c
#define TRACE_REG_TM_TRACE_MMIO_WP0_LOW 0x0940
#define TRACE_REG_TM_TRACE_MMIO_WP1_LOW 0x0944
#define TRACE_REG_TM_TRACE_MMIO_WP2_LOW 0x0948
#define TRACE_REG_TM_TRACE_MMIO_WP3_LOW 0x094c
#define TRACE_REG_TM_TRACE_MMIO_WP0_HIGH 0x0950
#define TRACE_REG_TM_TRACE_MMIO_WP1_HIGH 0x0954
#define TRACE_REG_TM_TRACE_MMIO_WP2_HIGH 0x0958
#define TRACE_REG_TM_TRACE_MMIO_WP3_HIGH 0x095c
#define TRACE_REG_TM_FWTRACE_FIRST 0x0A00
#define TRACE_REG_TM_FWTRACE_MIDDLE 0x0A04
#define TRACE_REG_TM_FWTRACE_LAST 0x0A08

#define TRACE_REG_CREATE_TM_REGISTER_LIST { \
TRACE_REG_TM_TRACE_ADDR_A, \
TRACE_REG_TM_TRACE_ADDR_B, \
TRACE_REG_TM_TRACE_ADDR_C, \
TRACE_REG_TM_TRACE_ADDR_D, \
TRACE_REG_TM_TRACE_ENABLE_NPK, \
TRACE_REG_TM_TRACE_ENABLE_DDR, \
TRACE_REG_TM_TRACE_PER_PC, \
TRACE_REG_TM_TRACE_PER_BRANCH, \
TRACE_REG_TM_TRACE_HEADER, \
TRACE_REG_TM_TRACE_CFG, \
TRACE_REG_TM_TRACE_LOST_PACKETS, \
TRACE_REG_TM_TRACE_LP_CLEAR, \
TRACE_REG_TM_TRACE_LMRUN_MASK, \
TRACE_REG_TM_TRACE_LMRUN_PC_LOW, \
TRACE_REG_TM_TRACE_LMRUN_PC_HIGH, \
TRACE_REG_TM_TRACE_MMIO_SEL, \
TRACE_REG_TM_TRACE_MMIO_WP0_LOW, \
TRACE_REG_TM_TRACE_MMIO_WP1_LOW, \
TRACE_REG_TM_TRACE_MMIO_WP2_LOW, \
TRACE_REG_TM_TRACE_MMIO_WP3_LOW, \
TRACE_REG_TM_TRACE_MMIO_WP0_HIGH, \
TRACE_REG_TM_TRACE_MMIO_WP1_HIGH, \
TRACE_REG_TM_TRACE_MMIO_WP2_HIGH, \
TRACE_REG_TM_TRACE_MMIO_WP3_HIGH, \
TRACE_REG_END_MARK \
}

/*
* Following exists only in (I)SP address space:
* TM_FWTRACE_FIRST, TM_FWTRACE_MIDDLE, TM_FWTRACE_LAST
*/

#define TRACE_REG_GPC_RESET 0x000
#define TRACE_REG_GPC_OVERALL_ENABLE 0x004
#define TRACE_REG_GPC_TRACE_HEADER 0x008
#define TRACE_REG_GPC_TRACE_ADDRESS 0x00C
#define TRACE_REG_GPC_TRACE_NPK_EN 0x010
#define TRACE_REG_GPC_TRACE_DDR_EN 0x014
#define TRACE_REG_GPC_TRACE_LPKT_CLEAR 0x018
#define TRACE_REG_GPC_TRACE_LPKT 0x01C

#define TRACE_REG_GPC_ENABLE_ID0 0x020
#define TRACE_REG_GPC_ENABLE_ID1 0x024
#define TRACE_REG_GPC_ENABLE_ID2 0x028
#define TRACE_REG_GPC_ENABLE_ID3 0x02c

#define TRACE_REG_GPC_VALUE_ID0 0x030
#define TRACE_REG_GPC_VALUE_ID1 0x034
#define TRACE_REG_GPC_VALUE_ID2 0x038
#define TRACE_REG_GPC_VALUE_ID3 0x03c

#define TRACE_REG_GPC_CNT_INPUT_SELECT_ID0 0x040
#define TRACE_REG_GPC_CNT_INPUT_SELECT_ID1 0x044
#define TRACE_REG_GPC_CNT_INPUT_SELECT_ID2 0x048
#define TRACE_REG_GPC_CNT_INPUT_SELECT_ID3 0x04c

#define TRACE_REG_GPC_CNT_START_SELECT_ID0 0x050
#define TRACE_REG_GPC_CNT_START_SELECT_ID1 0x054
#define TRACE_REG_GPC_CNT_START_SELECT_ID2 0x058
#define TRACE_REG_GPC_CNT_START_SELECT_ID3 0x05c

#define TRACE_REG_GPC_CNT_STOP_SELECT_ID0 0x060
#define TRACE_REG_GPC_CNT_STOP_SELECT_ID1 0x064
#define TRACE_REG_GPC_CNT_STOP_SELECT_ID2 0x068
#define TRACE_REG_GPC_CNT_STOP_SELECT_ID3 0x06c

#define TRACE_REG_GPC_CNT_MSG_SELECT_ID0 0x070
#define TRACE_REG_GPC_CNT_MSG_SELECT_ID1 0x074
#define TRACE_REG_GPC_CNT_MSG_SELECT_ID2 0x078
#define TRACE_REG_GPC_CNT_MSG_SELECT_ID3 0x07c

#define TRACE_REG_GPC_CNT_MSG_PLOAD_SELECT_ID0 0x080
#define TRACE_REG_GPC_CNT_MSG_PLOAD_SELECT_ID1 0x084
#define TRACE_REG_GPC_CNT_MSG_PLOAD_SELECT_ID2 0x088
#define TRACE_REG_GPC_CNT_MSG_PLOAD_SELECT_ID3 0x08c

#define TRACE_REG_GPC_IRQ_TRIGGER_VALUE_ID0 0x090
#define TRACE_REG_GPC_IRQ_TRIGGER_VALUE_ID1 0x094
#define TRACE_REG_GPC_IRQ_TRIGGER_VALUE_ID2 0x098
#define TRACE_REG_GPC_IRQ_TRIGGER_VALUE_ID3 0x09c

#define TRACE_REG_GPC_IRQ_TIMER_SELECT_ID0 0x0a0
#define TRACE_REG_GPC_IRQ_TIMER_SELECT_ID1 0x0a4
#define TRACE_REG_GPC_IRQ_TIMER_SELECT_ID2 0x0a8
#define TRACE_REG_GPC_IRQ_TIMER_SELECT_ID3 0x0ac

#define TRACE_REG_GPC_IRQ_ENABLE_ID0 0x0b0
#define TRACE_REG_GPC_IRQ_ENABLE_ID1 0x0b4
#define TRACE_REG_GPC_IRQ_ENABLE_ID2 0x0b8
#define TRACE_REG_GPC_IRQ_ENABLE_ID3 0x0bc

#define TRACE_REG_CREATE_GPC_REGISTER_LIST { \
TRACE_REG_GPC_RESET, \
TRACE_REG_GPC_OVERALL_ENABLE, \
TRACE_REG_GPC_TRACE_HEADER, \
TRACE_REG_GPC_TRACE_ADDRESS, \
TRACE_REG_GPC_TRACE_NPK_EN, \
TRACE_REG_GPC_TRACE_DDR_EN, \
TRACE_REG_GPC_TRACE_LPKT_CLEAR, \
TRACE_REG_GPC_TRACE_LPKT, \
TRACE_REG_GPC_ENABLE_ID0, \
TRACE_REG_GPC_ENABLE_ID1, \
TRACE_REG_GPC_ENABLE_ID2, \
TRACE_REG_GPC_ENABLE_ID3, \
TRACE_REG_GPC_VALUE_ID0, \
TRACE_REG_GPC_VALUE_ID1, \
TRACE_REG_GPC_VALUE_ID2, \
TRACE_REG_GPC_VALUE_ID3, \
TRACE_REG_GPC_CNT_INPUT_SELECT_ID0, \
TRACE_REG_GPC_CNT_INPUT_SELECT_ID1, \
TRACE_REG_GPC_CNT_INPUT_SELECT_ID2, \
TRACE_REG_GPC_CNT_INPUT_SELECT_ID3, \
TRACE_REG_GPC_CNT_START_SELECT_ID0, \
TRACE_REG_GPC_CNT_START_SELECT_ID1, \
TRACE_REG_GPC_CNT_START_SELECT_ID2, \
TRACE_REG_GPC_CNT_START_SELECT_ID3, \
TRACE_REG_GPC_CNT_STOP_SELECT_ID0, \
TRACE_REG_GPC_CNT_STOP_SELECT_ID1, \
TRACE_REG_GPC_CNT_STOP_SELECT_ID2, \
TRACE_REG_GPC_CNT_STOP_SELECT_ID3, \
TRACE_REG_GPC_CNT_MSG_SELECT_ID0, \
TRACE_REG_GPC_CNT_MSG_SELECT_ID1, \
TRACE_REG_GPC_CNT_MSG_SELECT_ID2, \
TRACE_REG_GPC_CNT_MSG_SELECT_ID3, \
TRACE_REG_GPC_CNT_MSG_PLOAD_SELECT_ID0, \
TRACE_REG_GPC_CNT_MSG_PLOAD_SELECT_ID1, \
TRACE_REG_GPC_CNT_MSG_PLOAD_SELECT_ID2, \
TRACE_REG_GPC_CNT_MSG_PLOAD_SELECT_ID3, \
TRACE_REG_GPC_IRQ_TRIGGER_VALUE_ID0, \
TRACE_REG_GPC_IRQ_TRIGGER_VALUE_ID1, \
TRACE_REG_GPC_IRQ_TRIGGER_VALUE_ID2, \
TRACE_REG_GPC_IRQ_TRIGGER_VALUE_ID3, \
TRACE_REG_GPC_IRQ_TIMER_SELECT_ID0, \
TRACE_REG_GPC_IRQ_TIMER_SELECT_ID1, \
TRACE_REG_GPC_IRQ_TIMER_SELECT_ID2, \
TRACE_REG_GPC_IRQ_TIMER_SELECT_ID3, \
TRACE_REG_GPC_IRQ_ENABLE_ID0, \
TRACE_REG_GPC_IRQ_ENABLE_ID1, \
TRACE_REG_GPC_IRQ_ENABLE_ID2, \
TRACE_REG_GPC_IRQ_ENABLE_ID3, \
TRACE_REG_END_MARK \
}

/* CSI2 legacy receiver trace registers */
#define TRACE_REG_CSI2_TM_RESET_REG_IDX 0x0000
#define TRACE_REG_CSI2_TM_OVERALL_ENABLE_REG_IDX 0x0004
#define TRACE_REG_CSI2_TM_TRACE_HEADER_REG_IDX 0x0008
#define TRACE_REG_CSI2_TM_TRACE_ADDRESS_REG_IDX 0x000c
#define TRACE_REG_CSI2_TM_TRACE_HEADER_VAL 0xf
#define TRACE_REG_CSI2_TM_TRACE_ADDRESS_VAL 0x100218
#define TRACE_REG_CSI2_TM_MONITOR_ID 0x8

/* 0 <= n <= 3 */
#define TRACE_REG_CSI2_TM_TRACE_NPK_EN_REG_IDX_P(n) (0x0010 + (n) * 4)
#define TRACE_REG_CSI2_TM_TRACE_DDR_EN_REG_IDX_P(n) (0x0020 + (n) * 4)
#define TRACE_CSI2_TM_EVENT_FE(vc) (BIT(0) << ((vc) * 6))
#define TRACE_CSI2_TM_EVENT_FS(vc) (BIT(1) << ((vc) * 6))
#define TRACE_CSI2_TM_EVENT_PE(vc) (BIT(2) << ((vc) * 6))
#define TRACE_CSI2_TM_EVENT_PS(vc) (BIT(3) << ((vc) * 6))
#define TRACE_CSI2_TM_EVENT_LE(vc) (BIT(4) << ((vc) * 6))
#define TRACE_CSI2_TM_EVENT_LS(vc) (BIT(5) << ((vc) * 6))

#define TRACE_REG_CSI2_TM_TRACE_LPKT_CLEAR_REG_IDX 0x0030
#define TRACE_REG_CSI2_TM_TRACE_LPKT_REG_IDX 0x0034

/* 0 <= n <= 7 */
#define TRACE_REG_CSI2_TM_ENABLE_REG_ID_N(n) (0x0038 + (n) * 4)
#define TRACE_REG_CSI2_TM_VALUE_REG_ID_N(n) (0x0058 + (n) * 4)
#define TRACE_REG_CSI2_TM_CNT_INPUT_SELECT_REG_ID_N(n) (0x0078 + (n) * 4)
#define TRACE_REG_CSI2_TM_CNT_START_SELECT_REG_ID_N(n) (0x0098 + (n) * 4)
#define TRACE_REG_CSI2_TM_CNT_STOP_SELECT_REG_ID_N(n) (0x00b8 + (n) * 4)
#define TRACE_REG_CSI2_TM_IRQ_TRIGGER_VALUE_REG_ID_N(n) (0x00d8 + (n) * 4)
#define TRACE_REG_CSI2_TM_IRQ_TIMER_SELECT_REG_ID_N(n) (0x00f8 + (n) * 4)
#define TRACE_REG_CSI2_TM_IRQ_ENABLE_REG_ID_N(n) (0x0118 + (n) * 4)

/* CSI2_3PH combo receiver trace registers */
#define TRACE_REG_CSI2_3PH_TM_RESET_REG_IDX 0x0000
#define TRACE_REG_CSI2_3PH_TM_OVERALL_ENABLE_REG_IDX 0x0004
#define TRACE_REG_CSI2_3PH_TM_TRACE_HEADER_REG_IDX 0x0008
#define TRACE_REG_CSI2_3PH_TM_TRACE_ADDRESS_REG_IDX 0x000c
#define TRACE_REG_CSI2_3PH_TM_TRACE_ADDRESS_VAL 0x100258
#define TRACE_REG_CSI2_3PH_TM_MONITOR_ID 0x9

/* 0 <= n <= 5 */
#define TRACE_REG_CSI2_3PH_TM_TRACE_NPK_EN_REG_IDX_P(n) (0x0010 + (n) * 4)
#define TRACE_REG_CSI2_3PH_TM_TRACE_DDR_EN_REG_IDX_P(n) (0x0028 + (n) * 4)

#define TRACE_REG_CSI2_3PH_TM_TRACE_LPKT_CLEAR_REG_IDX 0x0040
#define TRACE_REG_CSI2_3PH_TM_TRACE_LPKT_REG_IDX 0x0044

/* 0 <= n <= 7 */
#define TRACE_REG_CSI2_3PH_TM_ENABLE_REG_ID_N(n) (0x0048 + (n) * 4)
#define TRACE_REG_CSI2_3PH_TM_VALUE_REG_ID_N(n) (0x0068 + (n) * 4)
#define TRACE_REG_CSI2_3PH_TM_CNT_INPUT_SELECT_REG_ID_N(n) (0x0088 + (n) * 4)
#define TRACE_REG_CSI2_3PH_TM_CNT_START_SELECT_REG_ID_N(n) (0x00a8 + (n) * 4)
#define TRACE_REG_CSI2_3PH_TM_CNT_STOP_SELECT_REG_ID_N(n) (0x00c8 + (n) * 4)
#define TRACE_REG_CSI2_3PH_TM_IRQ_TRIGGER_VALUE_REG_ID_N(n) (0x00e8 + (n) * 4)
#define TRACE_REG_CSI2_3PH_TM_IRQ_TIMER_SELECT_REG_ID_N(n) (0x0108 + (n) * 4)
#define TRACE_REG_CSI2_3PH_TM_IRQ_ENABLE_REG_ID_N(n) (0x0128 + (n) * 4)

/* SIG2CIO trace monitors */
#define TRACE_REG_SIG2CIO_ADDRESS 0x0000
#define TRACE_REG_SIG2CIO_WDATA 0x0004
#define TRACE_REG_SIG2CIO_MASK 0x0008
#define TRACE_REG_SIG2CIO_GROUP_CFG 0x000c
#define TRACE_REG_SIG2CIO_STICKY 0x0010
#define TRACE_REG_SIG2CIO_RST_STICKY 0x0014
#define TRACE_REG_SIG2CIO_MANUAL_RST_STICKY 0x0018
#define TRACE_REG_SIG2CIO_STATUS 0x001c
/* Size of on SIG2CIO block */
#define TRACE_REG_SIG2CIO_SIZE_OF 0x0020

struct ipu_trace;
struct ipu_subsystem_trace_config;

enum ipu_trace_block_type {
IPU_TRACE_BLOCK_TUN = 0, /* Trace unit */
IPU_TRACE_BLOCK_TM, /* Trace monitor */
IPU_TRACE_BLOCK_GPC, /* General purpose control */
IPU_TRACE_CSI2, /* CSI2 legacy receiver */
IPU_TRACE_CSI2_3PH, /* CSI2 combo receiver */
IPU_TRACE_SIG2CIOS,
IPU_TRACE_TIMER_RST, /* Trace reset control timer */
IPU_TRACE_BLOCK_END /* End of list */
};

struct ipu_trace_block {
u32 offset; /* Offset to block inside subsystem */
enum ipu_trace_block_type type;
};

int ipu_trace_add(struct ipu_device *isp);
int ipu_trace_debugfs_add(struct ipu_device *isp, struct dentry *dir);
void ipu_trace_release(struct ipu_device *isp);
int ipu_trace_init(struct ipu_device *isp, void __iomem *base,
struct device *dev, struct ipu_trace_block *blocks);
void ipu_trace_restore(struct device *dev);
void ipu_trace_uninit(struct device *dev);
void ipu_trace_stop(struct device *dev);
#endif
798 changes: 798 additions & 0 deletions drivers/media/pci/intel/ipu.c

Large diffs are not rendered by default.

106 changes: 106 additions & 0 deletions drivers/media/pci/intel/ipu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2013 - 2020 Intel Corporation */

#ifndef IPU_H
#define IPU_H

#include <linux/ioport.h>
#include <linux/list.h>
#include <uapi/linux/media.h>
#include <linux/version.h>

#include "ipu-pdata.h"
#include "ipu-bus.h"
#include "ipu-buttress.h"
#include "ipu-trace.h"

#define IPU6_PCI_ID 0x9a19
#define IPU6SE_PCI_ID 0x4e19

enum ipu_version {
IPU_VER_INVALID = 0,
IPU_VER_6,
IPU_VER_6SE,
};

/*
* IPU version definitions to reflect the IPU driver changes.
* Both ISYS and PSYS share the same version.
*/
#define IPU_MAJOR_VERSION 1
#define IPU_MINOR_VERSION 0
#define IPU_DRIVER_VERSION (IPU_MAJOR_VERSION << 16 | IPU_MINOR_VERSION)

/* processing system frequency: 25Mhz x ratio, Legal values [8,32] */
#define PS_FREQ_CTL_DEFAULT_RATIO 0x12

/* input system frequency: 1600Mhz / divisor. Legal values [2,8] */
#define IS_FREQ_SOURCE 1600000000
#define IS_FREQ_CTL_DIVISOR 0x4

/*
* ISYS DMA can overshoot. For higher resolutions over allocation is one line
* but it must be at minimum 1024 bytes. Value could be different in
* different versions / generations thus provide it via platform data.
*/
#define IPU_ISYS_OVERALLOC_MIN 1024

/*
* Physical pages in GDA is 128, page size is 2K for IPU6, 1K for others.
*/
#define IPU_DEVICE_GDA_NR_PAGES 128

/*
* Virtualization factor to calculate the available virtual pages.
*/
#define IPU_DEVICE_GDA_VIRT_FACTOR 32

struct pci_dev;
struct list_head;
struct firmware;

#define NR_OF_MMU_RESOURCES 2

struct ipu_device {
struct pci_dev *pdev;
struct list_head devices;
struct ipu_bus_device *isys;
struct ipu_bus_device *psys;
struct ipu_buttress buttress;

const struct firmware *cpd_fw;
const char *cpd_fw_name;
u64 *pkg_dir;
dma_addr_t pkg_dir_dma_addr;
unsigned int pkg_dir_size;
struct sg_table fw_sgt;

void __iomem *base;
#ifdef CONFIG_DEBUG_FS
struct dentry *ipu_dir;
#endif
struct ipu_trace *trace;
bool flr_done;
bool ipc_reinit;
bool secure_mode;

int (*cpd_fw_reload)(struct ipu_device *isp);
};

#define IPU_DMA_MASK 39
#define IPU_LIB_CALL_TIMEOUT_MS 2000
#define IPU_PSYS_CMD_TIMEOUT_MS 2000
#define IPU_PSYS_OPEN_TIMEOUT_US 50
#define IPU_PSYS_OPEN_RETRY (10000 / IPU_PSYS_OPEN_TIMEOUT_US)

int ipu_fw_authenticate(void *data, u64 val);
void ipu_configure_spc(struct ipu_device *isp,
const struct ipu_hw_variants *hw_variant,
int pkg_dir_idx, void __iomem *base, u64 *pkg_dir,
dma_addr_t pkg_dir_dma_addr);
int request_cpd_fw(const struct firmware **firmware_p, const char *name,
struct device *device);
extern enum ipu_version ipu_ver;
void ipu_internal_pdata_init(void);

#endif /* IPU_H */
59 changes: 59 additions & 0 deletions drivers/media/pci/intel/ipu6/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2017 - 2020 Intel Corporation.

ifneq ($(EXTERNAL_BUILD), 1)
srcpath := $(srctree)
endif

ccflags-y += -DHAS_DUAL_CMD_CTX_SUPPORT=0 -DIPU_TPG_FRAME_SYNC -DIPU_PSYS_GPC \
-DIPU_ISYS_GPC

intel-ipu6-objs += ../ipu.o \
../ipu-bus.o \
../ipu-dma.o \
../ipu-mmu.o \
../ipu-buttress.o \
../ipu-trace.o \
../ipu-cpd.o \
ipu6.o \
../ipu-fw-com.o

obj-$(CONFIG_VIDEO_INTEL_IPU) += intel-ipu6.o

intel-ipu6-isys-objs += ../ipu-isys.o \
../ipu-isys-csi2.o \
ipu6-isys.o \
ipu6-isys-phy.o \
ipu6-isys-csi2.o \
ipu6-isys-gpc.o \
../ipu-isys-csi2-be-soc.o \
../ipu-isys-csi2-be.o \
../ipu-fw-isys.o \
../ipu-isys-video.o \
../ipu-isys-queue.o \
../ipu-isys-subdev.o \
../ipu-isys-tpg.o

obj-$(CONFIG_VIDEO_INTEL_IPU) += intel-ipu6-isys.o

intel-ipu6-psys-objs += ../ipu-psys.o \
ipu6-psys.o \
ipu-resources.o \
ipu6-psys-gpc.o \
ipu6-l-scheduler.o \
ipu6-ppg.o

intel-ipu6-psys-objs += ipu-fw-resources.o \
ipu6-fw-resources.o \
ipu6se-fw-resources.o \
../ipu-fw-psys.o

ifeq ($(CONFIG_COMPAT),y)
intel-ipu6-psys-objs += ../ipu-psys-compat32.o
endif

obj-$(CONFIG_VIDEO_INTEL_IPU) += intel-ipu6-psys.o

ccflags-y += -I$(srcpath)/$(src)/../../../../../include/
ccflags-y += -I$(srcpath)/$(src)/../
ccflags-y += -I$(srcpath)/$(src)/
103 changes: 103 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu-fw-resources.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2015 - 2019 Intel Corporation

#include <linux/err.h>
#include <linux/string.h>

#include "ipu-psys.h"
#include "ipu-fw-psys.h"
#include "ipu6-platform-resources.h"
#include "ipu6se-platform-resources.h"

/********** Generic resource handling **********/

/*
* Extension library gives byte offsets to its internal structures.
* use those offsets to update fields. Without extension lib access
* structures directly.
*/
const struct ipu6_psys_hw_res_variant *var = &hw_var;

int ipu_fw_psys_set_process_cell_id(struct ipu_fw_psys_process *ptr, u8 index,
u8 value)
{
struct ipu_fw_psys_process_group *parent =
(struct ipu_fw_psys_process_group *)((char *)ptr +
ptr->parent_offset);

ptr->cells[index] = value;
parent->resource_bitmap |= 1 << value;

return 0;
}

u8 ipu_fw_psys_get_process_cell_id(struct ipu_fw_psys_process *ptr, u8 index)
{
return ptr->cells[index];
}

int ipu_fw_psys_clear_process_cell(struct ipu_fw_psys_process *ptr)
{
struct ipu_fw_psys_process_group *parent;
u8 cell_id = ipu_fw_psys_get_process_cell_id(ptr, 0);
int retval = -1;
u8 value;

parent = (struct ipu_fw_psys_process_group *)((char *)ptr +
ptr->parent_offset);

value = var->cell_num;
if ((1 << cell_id) != 0 &&
((1 << cell_id) & parent->resource_bitmap)) {
ipu_fw_psys_set_process_cell_id(ptr, 0, value);
parent->resource_bitmap &= ~(1 << cell_id);
retval = 0;
}

return retval;
}

int ipu_fw_psys_set_proc_dev_chn(struct ipu_fw_psys_process *ptr, u16 offset,
u16 value)
{
if (var->set_proc_dev_chn)
return var->set_proc_dev_chn(ptr, offset, value);

WARN(1, "ipu6 psys res var is not initialised correctly.");
return 0;
}

int ipu_fw_psys_set_proc_dfm_bitmap(struct ipu_fw_psys_process *ptr,
u16 id, u32 bitmap,
u32 active_bitmap)
{
if (var->set_proc_dfm_bitmap)
return var->set_proc_dfm_bitmap(ptr, id, bitmap,
active_bitmap);

WARN(1, "ipu6 psys res var is not initialised correctly.");
return 0;
}

int ipu_fw_psys_set_process_ext_mem(struct ipu_fw_psys_process *ptr,
u16 type_id, u16 mem_id, u16 offset)
{
if (var->set_proc_ext_mem)
return var->set_proc_ext_mem(ptr, type_id, mem_id, offset);

WARN(1, "ipu6 psys res var is not initialised correctly.");
return 0;
}

int ipu_fw_psys_get_program_manifest_by_process(
struct ipu_fw_generic_program_manifest *gen_pm,
const struct ipu_fw_psys_program_group_manifest *pg_manifest,
struct ipu_fw_psys_process *process)
{
if (var->get_pgm_by_proc)
return var->get_pgm_by_proc(gen_pm, pg_manifest, process);

WARN(1, "ipu6 psys res var is not initialised correctly.");
return 0;
}

315 changes: 315 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu-platform-buttress-regs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2020 Intel Corporation */

#ifndef IPU_PLATFORM_BUTTRESS_REGS_H
#define IPU_PLATFORM_BUTTRESS_REGS_H

/* IS_WORKPOINT_REQ */
#define IPU_BUTTRESS_REG_IS_FREQ_CTL 0x34
/* PS_WORKPOINT_REQ */
#define IPU_BUTTRESS_REG_PS_FREQ_CTL 0x38

#define IPU_BUTTRESS_IS_FREQ_RATIO_MASK 0xff
#define IPU_BUTTRESS_PS_FREQ_RATIO_MASK 0xff

#define IPU_IS_FREQ_MAX 533
#define IPU_IS_FREQ_MIN 200
#define IPU_PS_FREQ_MAX 450
#define IPU_IS_FREQ_RATIO_BASE 25
#define IPU_PS_FREQ_RATIO_BASE 25
#define IPU_BUTTRESS_IS_FREQ_CTL_DIVISOR_MASK 0xff
#define IPU_BUTTRESS_PS_FREQ_CTL_DIVISOR_MASK 0xff

/* should be tuned for real silicon */
#define IPU_IS_FREQ_CTL_DEFAULT_RATIO 0x08
#define IPU_PS_FREQ_CTL_DEFAULT_RATIO 0x10

#define IPU_IS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO 0x10
#define IPU_PS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO 0x0708

#define IPU_BUTTRESS_PWR_STATE_IS_PWR_SHIFT 3
#define IPU_BUTTRESS_PWR_STATE_IS_PWR_MASK \
(0x3 << IPU_BUTTRESS_PWR_STATE_IS_PWR_SHIFT)

#define IPU_BUTTRESS_PWR_STATE_PS_PWR_SHIFT 6
#define IPU_BUTTRESS_PWR_STATE_PS_PWR_MASK \
(0x3 << IPU_BUTTRESS_PWR_STATE_PS_PWR_SHIFT)

#define IPU_BUTTRESS_PWR_STATE_DN_DONE 0x0
#define IPU_BUTTRESS_PWR_STATE_UP_PROCESS 0x1
#define IPU_BUTTRESS_PWR_STATE_DN_PROCESS 0x2
#define IPU_BUTTRESS_PWR_STATE_UP_DONE 0x3

#define IPU_BUTTRESS_REG_FPGA_SUPPORT_0 0x270
#define IPU_BUTTRESS_REG_FPGA_SUPPORT_1 0x274
#define IPU_BUTTRESS_REG_FPGA_SUPPORT_2 0x278
#define IPU_BUTTRESS_REG_FPGA_SUPPORT_3 0x27c
#define IPU_BUTTRESS_REG_FPGA_SUPPORT_4 0x280
#define IPU_BUTTRESS_REG_FPGA_SUPPORT_5 0x284
#define IPU_BUTTRESS_REG_FPGA_SUPPORT_6 0x288
#define IPU_BUTTRESS_REG_FPGA_SUPPORT_7 0x28c

#define BUTTRESS_REG_WDT 0x8
#define BUTTRESS_REG_BTRS_CTRL 0xc
#define BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC0 BIT(0)
#define BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC1 BIT(1)

#define BUTTRESS_REG_FW_RESET_CTL 0x30
#define BUTTRESS_FW_RESET_CTL_START BIT(0)
#define BUTTRESS_FW_RESET_CTL_DONE BIT(1)

#define BUTTRESS_REG_IS_FREQ_CTL 0x34

#define BUTTRESS_IS_FREQ_CTL_DIVISOR_MASK 0xf

#define BUTTRESS_REG_PS_FREQ_CTL 0x38

#define BUTTRESS_PS_FREQ_CTL_RATIO_MASK 0xff

#define BUTTRESS_FREQ_CTL_START BIT(31)
#define BUTTRESS_FREQ_CTL_START_SHIFT 31
#define BUTTRESS_FREQ_CTL_QOS_FLOOR_SHIFT 8
#define BUTTRESS_FREQ_CTL_QOS_FLOOR_MASK (0xff << 8)

#define BUTTRESS_REG_PWR_STATE 0x5c

#define BUTTRESS_PWR_STATE_IS_PWR_SHIFT 3
#define BUTTRESS_PWR_STATE_IS_PWR_MASK (0x3 << 3)

#define BUTTRESS_PWR_STATE_PS_PWR_SHIFT 6
#define BUTTRESS_PWR_STATE_PS_PWR_MASK (0x3 << 6)

#define BUTTRESS_PWR_STATE_RESET 0x0
#define BUTTRESS_PWR_STATE_PWR_ON_DONE 0x1
#define BUTTRESS_PWR_STATE_PWR_RDY 0x3
#define BUTTRESS_PWR_STATE_PWR_IDLE 0x4

#define BUTTRESS_PWR_STATE_HH_STATUS_SHIFT 11
#define BUTTRESS_PWR_STATE_HH_STATUS_MASK (0x3 << 11)

enum {
BUTTRESS_PWR_STATE_HH_STATE_IDLE,
BUTTRESS_PWR_STATE_HH_STATE_IN_PRGS,
BUTTRESS_PWR_STATE_HH_STATE_DONE,
BUTTRESS_PWR_STATE_HH_STATE_ERR,
};

#define BUTTRESS_PWR_STATE_IS_PWR_FSM_SHIFT 19
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_MASK (0xf << 19)

#define BUTTRESS_PWR_STATE_IS_PWR_FSM_IDLE 0x0
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_PLL_CMP 0x1
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_CLKACK 0x2
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_PG_ACK 0x3
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_RST_ASSRT_CYCLES 0x4
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_STOP_CLK_CYCLES1 0x5
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_STOP_CLK_CYCLES2 0x6
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_RST_DEASSRT_CYCLES 0x7
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_FUSE_WR_CMP 0x8
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_BRK_POINT 0x9
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_IS_RDY 0xa
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_HALT_HALTED 0xb
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_RST_DURATION_CNT3 0xc
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_CLKACK_PD 0xd
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_PD_BRK_POINT 0xe
#define BUTTRESS_PWR_STATE_IS_PWR_FSM_WAIT_4_PD_PG_ACK0 0xf

#define BUTTRESS_PWR_STATE_PS_PWR_FSM_SHIFT 24
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_MASK (0x1f << 24)

#define BUTTRESS_PWR_STATE_PS_PWR_FSM_IDLE 0x0
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PU_PLL_IP_RDY 0x1
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_RO_PRE_CNT_EXH 0x2
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PU_VGI_PWRGOOD 0x3
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_RO_POST_CNT_EXH 0x4
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WR_PLL_RATIO 0x5
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PU_PLL_CMP 0x6
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PU_CLKACK 0x7
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_RST_ASSRT_CYCLES 0x8
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_STOP_CLK_CYCLES1 0x9
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_STOP_CLK_CYCLES2 0xa
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_RST_DEASSRT_CYCLES 0xb
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_PU_BRK_PNT 0xc
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_FUSE_ACCPT 0xd
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_PS_PWR_UP 0xf
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_4_HALTED 0x10
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_RESET_CNT3 0x11
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PD_CLKACK 0x12
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_PD_OFF_IND 0x13
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_DVFS_PH4 0x14
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_DVFS_PLL_CMP 0x15
#define BUTTRESS_PWR_STATE_PS_PWR_FSM_WAIT_DVFS_CLKACK 0x16

#define BUTTRESS_REG_SECURITY_CTL 0x300

#define BUTTRESS_SECURITY_CTL_FW_SECURE_MODE BIT(16)
#define BUTTRESS_SECURITY_CTL_FW_SETUP_SHIFT 0
#define BUTTRESS_SECURITY_CTL_FW_SETUP_MASK 0x1f

#define BUTTRESS_SECURITY_CTL_FW_SETUP_DONE 0x1
#define BUTTRESS_SECURITY_CTL_AUTH_DONE 0x2
#define BUTTRESS_SECURITY_CTL_AUTH_FAILED 0x8

#define BUTTRESS_REG_SENSOR_FREQ_CTL 0x16c

#define BUTTRESS_SENSOR_FREQ_CTL_OSC_OUT_FREQ_DEFAULT(i) \
(0x1b << ((i) * 10))
#define BUTTRESS_SENSOR_FREQ_CTL_OSC_OUT_FREQ_SHIFT(i) ((i) * 10)
#define BUTTRESS_SENSOR_FREQ_CTL_OSC_OUT_FREQ_MASK(i) \
(0x1ff << ((i) * 10))

#define BUTTRESS_SENSOR_CLK_FREQ_6P75MHZ 0x176
#define BUTTRESS_SENSOR_CLK_FREQ_8MHZ 0x164
#define BUTTRESS_SENSOR_CLK_FREQ_9P6MHZ 0x2
#define BUTTRESS_SENSOR_CLK_FREQ_12MHZ 0x1b2
#define BUTTRESS_SENSOR_CLK_FREQ_13P6MHZ 0x1ac
#define BUTTRESS_SENSOR_CLK_FREQ_14P4MHZ 0x1cc
#define BUTTRESS_SENSOR_CLK_FREQ_15P8MHZ 0x1a6
#define BUTTRESS_SENSOR_CLK_FREQ_16P2MHZ 0xca
#define BUTTRESS_SENSOR_CLK_FREQ_17P3MHZ 0x12e
#define BUTTRESS_SENSOR_CLK_FREQ_18P6MHZ 0x1c0
#define BUTTRESS_SENSOR_CLK_FREQ_19P2MHZ 0x0
#define BUTTRESS_SENSOR_CLK_FREQ_24MHZ 0xb2
#define BUTTRESS_SENSOR_CLK_FREQ_26MHZ 0xae
#define BUTTRESS_SENSOR_CLK_FREQ_27MHZ 0x196

#define BUTTRESS_SENSOR_FREQ_CTL_LJPLL_FB_RATIO_MASK 0xff
#define BUTTRESS_SENSOR_FREQ_CTL_SEL_MIPICLK_A_SHIFT 8
#define BUTTRESS_SENSOR_FREQ_CTL_SEL_MIPICLK_A_MASK (0x2 << 8)
#define BUTTRESS_SENSOR_FREQ_CTL_SEL_MIPICLK_C_SHIFT 10
#define BUTTRESS_SENSOR_FREQ_CTL_SEL_MIPICLK_C_MASK (0x2 << 10)
#define BUTTRESS_SENSOR_FREQ_CTL_LJPLL_FORCE_OFF_SHIFT 12
#define BUTTRESS_SENSOR_FREQ_CTL_LJPLL_REF_RATIO_SHIFT 14
#define BUTTRESS_SENSOR_FREQ_CTL_LJPLL_REF_RATIO_MASK (0x2 << 14)
#define BUTTRESS_SENSOR_FREQ_CTL_LJPLL_PVD_RATIO_SHIFT 16
#define BUTTRESS_SENSOR_FREQ_CTL_LJPLL_PVD_RATIO_MASK (0x2 << 16)
#define BUTTRESS_SENSOR_FREQ_CTL_LJPLL_OUTPUT_RATIO_SHIFT 18
#define BUTTRESS_SENSOR_FREQ_CTL_LJPLL_OUTPUT_RATIO_MASK (0x2 << 18)
#define BUTTRESS_SENSOR_FREQ_CTL_START_SHIFT 31

#define BUTTRESS_REG_SENSOR_CLK_CTL 0x170

/* 0 <= i <= 2 */
#define BUTTRESS_SENSOR_CLK_CTL_OSC_CLK_OUT_EN_SHIFT(i) ((i) * 2)
#define BUTTRESS_SENSOR_CLK_CTL_OSC_CLK_OUT_SEL_SHIFT(i) ((i) * 2 + 1)

#define BUTTRESS_REG_FW_SOURCE_BASE_LO 0x78
#define BUTTRESS_REG_FW_SOURCE_BASE_HI 0x7C
#define BUTTRESS_REG_FW_SOURCE_SIZE 0x80

#define BUTTRESS_REG_ISR_STATUS 0x90
#define BUTTRESS_REG_ISR_ENABLED_STATUS 0x94
#define BUTTRESS_REG_ISR_ENABLE 0x98
#define BUTTRESS_REG_ISR_CLEAR 0x9C

#define BUTTRESS_ISR_IS_IRQ BIT(0)
#define BUTTRESS_ISR_PS_IRQ BIT(1)
#define BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE BIT(2)
#define BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH BIT(3)
#define BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING BIT(4)
#define BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING BIT(5)
#define BUTTRESS_ISR_CSE_CSR_SET BIT(6)
#define BUTTRESS_ISR_ISH_CSR_SET BIT(7)
#define BUTTRESS_ISR_SPURIOUS_CMP BIT(8)
#define BUTTRESS_ISR_WATCHDOG_EXPIRED BIT(9)
#define BUTTRESS_ISR_PUNIT_2_IUNIT_IRQ BIT(10)
#define BUTTRESS_ISR_SAI_VIOLATION BIT(11)
#define BUTTRESS_ISR_HW_ASSERTION BIT(12)

#define BUTTRESS_REG_IU2CSEDB0 0x100

#define BUTTRESS_IU2CSEDB0_BUSY BIT(31)
#define BUTTRESS_IU2CSEDB0_SHORT_FORMAT_SHIFT 27
#define BUTTRESS_IU2CSEDB0_CLIENT_ID_SHIFT 10
#define BUTTRESS_IU2CSEDB0_IPC_CLIENT_ID_VAL 2

#define BUTTRESS_REG_IU2CSEDATA0 0x104

#define BUTTRESS_IU2CSEDATA0_IPC_BOOT_LOAD 1
#define BUTTRESS_IU2CSEDATA0_IPC_AUTH_RUN 2
#define BUTTRESS_IU2CSEDATA0_IPC_AUTH_REPLACE 3
#define BUTTRESS_IU2CSEDATA0_IPC_UPDATE_SECURE_TOUCH 16

#define BUTTRESS_CSE2IUDATA0_IPC_BOOT_LOAD_DONE 1
#define BUTTRESS_CSE2IUDATA0_IPC_AUTH_RUN_DONE 2
#define BUTTRESS_CSE2IUDATA0_IPC_AUTH_REPLACE_DONE 4
#define BUTTRESS_CSE2IUDATA0_IPC_UPDATE_SECURE_TOUCH_DONE 16

#define BUTTRESS_REG_IU2CSECSR 0x108

#define BUTTRESS_IU2CSECSR_IPC_PEER_COMP_ACTIONS_RST_PHASE1 BIT(0)
#define BUTTRESS_IU2CSECSR_IPC_PEER_COMP_ACTIONS_RST_PHASE2 BIT(1)
#define BUTTRESS_IU2CSECSR_IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE BIT(2)
#define BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ BIT(3)
#define BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID BIT(4)
#define BUTTRESS_IU2CSECSR_IPC_PEER_DEASSERTED_REG_VALID_REQ BIT(5)

#define BUTTRESS_REG_CSE2IUDB0 0x304
#define BUTTRESS_REG_CSE2IUCSR 0x30C
#define BUTTRESS_REG_CSE2IUDATA0 0x308

/* 0x20 == NACK, 0xf == unknown command */
#define BUTTRESS_CSE2IUDATA0_IPC_NACK 0xf20
#define BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK 0xffff

#define BUTTRESS_REG_ISH2IUCSR 0x50
#define BUTTRESS_REG_ISH2IUDB0 0x54
#define BUTTRESS_REG_ISH2IUDATA0 0x58

#define BUTTRESS_REG_IU2ISHDB0 0x10C
#define BUTTRESS_REG_IU2ISHDATA0 0x110
#define BUTTRESS_REG_IU2ISHDATA1 0x114
#define BUTTRESS_REG_IU2ISHCSR 0x118

#define BUTTRESS_REG_ISH_START_DETECT 0x198
#define BUTTRESS_REG_ISH_START_DETECT_MASK 0x19C

#define BUTTRESS_REG_FABRIC_CMD 0x88

#define BUTTRESS_FABRIC_CMD_START_TSC_SYNC BIT(0)
#define BUTTRESS_FABRIC_CMD_IS_DRAIN BIT(4)

#define BUTTRESS_REG_TSW_CTL 0x120
#define BUTTRESS_TSW_CTL_SOFT_RESET BIT(8)

#define BUTTRESS_REG_TSC_LO 0x164
#define BUTTRESS_REG_TSC_HI 0x168

#define BUTTRESS_REG_CSI2_PORT_CONFIG_AB 0x200
#define BUTTRESS_CSI2_PORT_CONFIG_AB_MUX_MASK 0x1f
#define BUTTRESS_CSI2_PORT_CONFIG_AB_COMBO_SHIFT_B0 16

#define BUTTRESS_REG_PS_FREQ_CAPABILITIES 0xf7498

#define BUTTRESS_PS_FREQ_CAPABILITIES_LAST_RESOLVED_RATIO_SHIFT 24
#define BUTTRESS_PS_FREQ_CAPABILITIES_LAST_RESOLVED_RATIO_MASK (0xff << 24)
#define BUTTRESS_PS_FREQ_CAPABILITIES_MAX_RATIO_SHIFT 16
#define BUTTRESS_PS_FREQ_CAPABILITIES_MAX_RATIO_MASK (0xff << 16)
#define BUTTRESS_PS_FREQ_CAPABILITIES_EFFICIENT_RATIO_SHIFT 8
#define BUTTRESS_PS_FREQ_CAPABILITIES_EFFICIENT_RATIO_MASK (0xff << 8)
#define BUTTRESS_PS_FREQ_CAPABILITIES_MIN_RATIO_SHIFT 0
#define BUTTRESS_PS_FREQ_CAPABILITIES_MIN_RATIO_MASK (0xff)

#define BUTTRESS_IRQS (BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING | \
BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE | \
BUTTRESS_ISR_IS_IRQ | \
BUTTRESS_ISR_PS_IRQ)

#define IPU6SE_ISYS_PHY_0_BASE 0x10000

/* only use BB0, BB2, BB4, and BB6 on PHY0 */
#define IPU6SE_ISYS_PHY_BB_NUM 4

/* offset from PHY base */
#define PHY_CSI_CFG 0xc0
#define PHY_CSI_RCOMP_CONTROL 0xc8
#define PHY_CSI_BSCAN_EXCLUDE 0xd8

#define PHY_CPHY_DLL_OVRD(x) (0x100 + 0x100 * (x))
#define PHY_DPHY_DLL_OVRD(x) (0x14c + 0x100 * (x))
#define PHY_CPHY_RX_CONTROL1(x) (0x110 + 0x100 * (x))
#define PHY_CPHY_RX_CONTROL2(x) (0x114 + 0x100 * (x))
#define PHY_DPHY_CFG(x) (0x148 + 0x100 * (x))
#define PHY_BB_AFE_CONFIG(x) (0x174 + 0x100 * (x))

#endif /* IPU_PLATFORM_BUTTRESS_REGS_H */
277 changes: 277 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu-platform-isys-csi2-reg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2020 Intel Corporation */

#ifndef IPU_PLATFORM_ISYS_CSI2_REG_H
#define IPU_PLATFORM_ISYS_CSI2_REG_H

#define CSI_REG_BASE 0x220000
#define CSI_REG_BASE_PORT(id) ((id) * 0x1000)

#define IPU_CSI_PORT_A_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(0))
#define IPU_CSI_PORT_B_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(1))
#define IPU_CSI_PORT_C_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(2))
#define IPU_CSI_PORT_D_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(3))
#define IPU_CSI_PORT_E_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(4))
#define IPU_CSI_PORT_F_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(5))
#define IPU_CSI_PORT_G_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(6))
#define IPU_CSI_PORT_H_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(7))

/* CSI Port Genral Purpose Registers */
#define CSI_REG_PORT_GPREG_SRST 0x0
#define CSI_REG_PORT_GPREG_CSI2_SLV_REG_SRST 0x4
#define CSI_REG_PORT_GPREG_CSI2_PORT_CONTROL 0x8

/*
* Port IRQs mapping events:
* IRQ0 - CSI_FE event
* IRQ1 - CSI_SYNC
* IRQ2 - S2M_SIDS0TO7
* IRQ3 - S2M_SIDS8TO15
*/
#define CSI_PORT_REG_BASE_IRQ_CSI 0x80
#define CSI_PORT_REG_BASE_IRQ_CSI_SYNC 0xA0
#define CSI_PORT_REG_BASE_IRQ_S2M_SIDS0TOS7 0xC0
#define CSI_PORT_REG_BASE_IRQ_S2M_SIDS8TOS15 0xE0

#define CSI_PORT_REG_BASE_IRQ_EDGE_OFFSET 0x0
#define CSI_PORT_REG_BASE_IRQ_MASK_OFFSET 0x4
#define CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET 0x8
#define CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET 0xc
#define CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET 0x10
#define CSI_PORT_REG_BASE_IRQ_LEVEL_NOT_PULSE_OFFSET 0x14

#define IPU6SE_CSI_RX_ERROR_IRQ_MASK 0x7ffff
#define IPU6_CSI_RX_ERROR_IRQ_MASK 0xfffff

#define CSI_RX_NUM_ERRORS_IN_IRQ 20
#define CSI_RX_NUM_IRQ 32

#define IPU_CSI_RX_IRQ_FS_VC 1
#define IPU_CSI_RX_IRQ_FE_VC 2

/* PPI2CSI */
#define CSI_REG_PPI2CSI_ENABLE 0x200
#define CSI_REG_PPI2CSI_CONFIG_PPI_INTF 0x204
#define PPI_INTF_CONFIG_NOF_ENABLED_DATALANES_SHIFT 3
#define PPI_INTF_CONFIG_RX_AUTO_CLKGATING_SHIFT 5
#define CSI_REG_PPI2CSI_CONFIG_CSI_FEATURE 0x208

enum CSI_PPI2CSI_CTRL {
CSI_PPI2CSI_DISABLE = 0,
CSI_PPI2CSI_ENABLE = 1,
};

/* CSI_FE */
#define CSI_REG_CSI_FE_ENABLE 0x280
#define CSI_REG_CSI_FE_MODE 0x284
#define CSI_REG_CSI_FE_MUX_CTRL 0x288
#define CSI_REG_CSI_FE_SYNC_CNTR_SEL 0x290

enum CSI_FE_ENABLE_TYPE {
CSI_FE_DISABLE = 0,
CSI_FE_ENABLE = 1,
};

enum CSI_FE_MODE_TYPE {
CSI_FE_DPHY_MODE = 0,
CSI_FE_CPHY_MODE = 1,
};

enum CSI_FE_INPUT_SELECTOR {
CSI_SENSOR_INPUT = 0,
CSI_MIPIGEN_INPUT = 1,
};

enum CSI_FE_SYNC_CNTR_SEL_TYPE {
CSI_CNTR_SENSOR_LINE_ID = (1 << 0),
CSI_CNTR_INT_LINE_PKT_ID = ~CSI_CNTR_SENSOR_LINE_ID,
CSI_CNTR_SENSOR_FRAME_ID = (1 << 1),
CSI_CNTR_INT_FRAME_PKT_ID = ~CSI_CNTR_SENSOR_FRAME_ID,
};

/* MIPI_PKT_GEN */
#define CSI_REG_PIXGEN_COM_BASE_OFFSET 0x300

#define IPU_CSI_PORT_A_PIXGEN_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(0) + CSI_REG_PIXGEN_COM_BASE_OFFSET)
#define IPU_CSI_PORT_B_PIXGEN_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(1) + CSI_REG_PIXGEN_COM_BASE_OFFSET)
#define IPU_CSI_PORT_C_PIXGEN_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(2) + CSI_REG_PIXGEN_COM_BASE_OFFSET)
#define IPU_CSI_PORT_D_PIXGEN_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(3) + CSI_REG_PIXGEN_COM_BASE_OFFSET)
#define IPU_CSI_PORT_E_PIXGEN_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(4) + CSI_REG_PIXGEN_COM_BASE_OFFSET)
#define IPU_CSI_PORT_F_PIXGEN_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(5) + CSI_REG_PIXGEN_COM_BASE_OFFSET)
#define IPU_CSI_PORT_G_PIXGEN_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(6) + CSI_REG_PIXGEN_COM_BASE_OFFSET)
#define IPU_CSI_PORT_H_PIXGEN_ADDR_OFFSET \
(CSI_REG_BASE + CSI_REG_BASE_PORT(7) + CSI_REG_PIXGEN_COM_BASE_OFFSET)

#define CSI_REG_PIXGEN_COM_ENABLE_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x300)
#define CSI_REG_PIXGEN_COM_DTYPE_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x304)
#define CSI_REG_PIXGEN_COM_VTYPE_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x308)
#define CSI_REG_PIXGEN_COM_VCHAN_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x30C)
#define CSI_REG_PIXGEN_COM_WCOUNT_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x310)
/* PRBS */
#define CSI_REG_PIXGEN_PRBS_RSTVAL_REG0_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x314)
#define CSI_REG_PIXGEN_PRBS_RSTVAL_REG1_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x318)
/* SYNC_GENERATOR_CONFIG */
#define CSI_REG_PIXGEN_SYNG_FREE_RUN_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x31C)
#define CSI_REG_PIXGEN_SYNG_PAUSE_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x320)
#define CSI_REG_PIXGEN_SYNG_NOF_FRAME_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x324)
#define CSI_REG_PIXGEN_SYNG_NOF_PIXEL_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x328)
#define CSI_REG_PIXGEN_SYNG_NOF_LINE_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x32C)
#define CSI_REG_PIXGEN_SYNG_HBLANK_CYC_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x330)
#define CSI_REG_PIXGEN_SYNG_VBLANK_CYC_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x334)
#define CSI_REG_PIXGEN_SYNG_STAT_HCNT_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x338)
#define CSI_REG_PIXGEN_SYNG_STAT_VCNT_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x33C)
#define CSI_REG_PIXGEN_SYNG_STAT_FCNT_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x340)
#define CSI_REG_PIXGEN_SYNG_STAT_DONE_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x344)
/* TPG */
#define CSI_REG_PIXGEN_TPG_MODE_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x348)
/* TPG: mask_cfg */
#define CSI_REG_PIXGEN_TPG_HCNT_MASK_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x34C)
#define CSI_REG_PIXGEN_TPG_VCNT_MASK_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x350)
#define CSI_REG_PIXGEN_TPG_XYCNT_MASK_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x354)
/* TPG: delta_cfg */
#define CSI_REG_PIXGEN_TPG_HCNT_DELTA_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x358)
#define CSI_REG_PIXGEN_TPG_VCNT_DELTA_REG_IDX(id) \
(CSI_REG_BASE_PORT(id) + 0x35C)
/* TPG: color_cfg */
#define CSI_REG_PIXGEN_TPG_R1_REG_IDX(id) (CSI_REG_BASE_PORT(id) + 0x360)
#define CSI_REG_PIXGEN_TPG_G1_REG_IDX(id) (CSI_REG_BASE_PORT(id) + 0x364)
#define CSI_REG_PIXGEN_TPG_B1_REG_IDX(id) (CSI_REG_BASE_PORT(id) + 0x368)
#define CSI_REG_PIXGEN_TPG_R2_REG_IDX(id) (CSI_REG_BASE_PORT(id) + 0x36C)
#define CSI_REG_PIXGEN_TPG_G2_REG_IDX(id) (CSI_REG_BASE_PORT(id) + 0x370)
#define CSI_REG_PIXGEN_TPG_B2_REG_IDX(id) (CSI_REG_BASE_PORT(id) + 0x374)

#define CSI_REG_PIXGEN_PRBS_RSTVAL_REG0 CSI_REG_PIXGEN_PRBS_RSTVAL_REG0_IDX(0)
#define CSI_REG_PIXGEN_PRBS_RSTVAL_REG1 CSI_REG_PIXGEN_PRBS_RSTVAL_REG1_IDX(0)
#define CSI_REG_PIXGEN_COM_ENABLE_REG CSI_REG_PIXGEN_COM_ENABLE_REG_IDX(0)
#define CSI_REG_PIXGEN_TPG_MODE_REG CSI_REG_PIXGEN_TPG_MODE_REG_IDX(0)
#define CSI_REG_PIXGEN_TPG_R1_REG CSI_REG_PIXGEN_TPG_R1_REG_IDX(0)
#define CSI_REG_PIXGEN_TPG_G1_REG CSI_REG_PIXGEN_TPG_G1_REG_IDX(0)
#define CSI_REG_PIXGEN_TPG_B1_REG CSI_REG_PIXGEN_TPG_B1_REG_IDX(0)
#define CSI_REG_PIXGEN_TPG_R2_REG CSI_REG_PIXGEN_TPG_R2_REG_IDX(0)
#define CSI_REG_PIXGEN_TPG_G2_REG CSI_REG_PIXGEN_TPG_G2_REG_IDX(0)
#define CSI_REG_PIXGEN_TPG_B2_REG CSI_REG_PIXGEN_TPG_B2_REG_IDX(0)
#define CSI_REG_PIXGEN_TPG_HCNT_MASK_REG CSI_REG_PIXGEN_TPG_HCNT_MASK_REG_IDX(0)
#define CSI_REG_PIXGEN_TPG_VCNT_MASK_REG CSI_REG_PIXGEN_TPG_VCNT_MASK_REG_IDX(0)
#define CSI_REG_PIXGEN_TPG_XYCNT_MASK_REG \
CSI_REG_PIXGEN_TPG_XYCNT_MASK_REG_IDX(0)

#define CSI_REG_PIXGEN_SYNG_NOF_FRAME_REG \
CSI_REG_PIXGEN_SYNG_NOF_FRAME_REG_IDX(0)
#define CSI_REG_PIXGEN_SYNG_NOF_LINE_REG \
CSI_REG_PIXGEN_SYNG_NOF_LINE_REG_IDX(0)
#define CSI_REG_PIXGEN_SYNG_HBLANK_CYC_REG \
CSI_REG_PIXGEN_SYNG_HBLANK_CYC_REG_IDX(0)
#define CSI_REG_PIXGEN_SYNG_VBLANK_CYC_REG \
CSI_REG_PIXGEN_SYNG_VBLANK_CYC_REG_IDX(0)
#define CSI_REG_PIXGEN_SYNG_NOF_PIXEL_REG \
CSI_REG_PIXGEN_SYNG_NOF_PIXEL_REG_IDX(0)
#define CSI_REG_PIXGEN_COM_WCOUNT_REG CSI_REG_PIXGEN_COM_WCOUNT_REG_IDX(0)
#define CSI_REG_PIXGEN_COM_DTYPE_REG CSI_REG_PIXGEN_COM_DTYPE_REG_IDX(0)
#define CSI_REG_PIXGEN_COM_VTYPE_REG CSI_REG_PIXGEN_COM_VTYPE_REG_IDX(0)
#define CSI_REG_PIXGEN_COM_VCHAN_REG CSI_REG_PIXGEN_COM_VCHAN_REG_IDX(0)
#define CSI_REG_PIXGEN_TPG_HCNT_DELTA_REG \
CSI_REG_PIXGEN_TPG_HCNT_DELTA_REG_IDX(0)
#define CSI_REG_PIXGEN_TPG_VCNT_DELTA_REG \
CSI_REG_PIXGEN_TPG_VCNT_DELTA_REG_IDX(0)

/* CSI HUB General Purpose Registers */
#define CSI_REG_HUB_GPREG_SRST (CSI_REG_BASE + 0x18000)
#define CSI_REG_HUB_GPREG_SLV_REG_SRST (CSI_REG_BASE + 0x18004)
#define CSI_REG_HUB_GPREG_PHY_CONTROL(id) \
(CSI_REG_BASE + 0x18008 + (id) * 0x8)
#define CSI_REG_HUB_GPREG_PHY_CONTROL_RESET BIT(4)
#define CSI_REG_HUB_GPREG_PHY_CONTROL_PWR_EN BIT(0)
#define CSI_REG_HUB_GPREG_PHY_STATUS(id) \
(CSI_REG_BASE + 0x1800c + (id) * 0x8)
#define CSI_REG_HUB_GPREG_PHY_STATUS_POWER_ACK BIT(0)
#define CSI_REG_HUB_GPREG_PHY_STATUS_PHY_READY BIT(4)

#define CSI_REG_HUB_DRV_ACCESS_PORT(id) (CSI_REG_BASE + 0x18018 + (id) * 4)
#define CSI_REG_HUB_FW_ACCESS_PORT(id) (CSI_REG_BASE + 0x17000 + (id) * 4)

enum CSI_PORT_CLK_GATING_SWITCH {
CSI_PORT_CLK_GATING_OFF = 0,
CSI_PORT_CLK_GATING_ON = 1,
};

#define CSI_REG_BASE_HUB_IRQ 0x18200

#define IPU_NUM_OF_DLANE_REG_PORT0 2
#define IPU_NUM_OF_DLANE_REG_PORT1 4
#define IPU_NUM_OF_DLANE_REG_PORT2 4
#define IPU_NUM_OF_DLANE_REG_PORT3 2
#define IPU_NUM_OF_DLANE_REG_PORT4 2
#define IPU_NUM_OF_DLANE_REG_PORT5 4
#define IPU_NUM_OF_DLANE_REG_PORT6 4
#define IPU_NUM_OF_DLANE_REG_PORT7 2

/* ipu6se support 2 SIPs, 2 port per SIP, 4 ports 0..3
* sip0 - 0, 1
* sip1 - 2, 3
* 0 and 2 support 4 data lanes, 1 and 3 support 2 data lanes
* all offset are base from isys base address
*/

#define CSI2_HUB_GPREG_SIP_SRST(sip) (0x238038 + (sip) * 4)
#define CSI2_HUB_GPREG_SIP_FB_PORT_CFG(sip) (0x238050 + (sip) * 4)

#define CSI2_HUB_GPREG_DPHY_TIMER_INCR (0x238040)
#define CSI2_HUB_GPREG_HPLL_FREQ (0x238044)
#define CSI2_HUB_GPREG_IS_CLK_RATIO (0x238048)
#define CSI2_HUB_GPREG_HPLL_FREQ_ISCLK_RATE_OVERRIDE (0x23804c)
#define CSI2_HUB_GPREG_PORT_CLKGATING_DISABLE (0x238058)
#define CSI2_HUB_GPREG_SIP0_CSI_RX_A_CONTROL (0x23805c)
#define CSI2_HUB_GPREG_SIP0_CSI_RX_B_CONTROL (0x238088)
#define CSI2_HUB_GPREG_SIP1_CSI_RX_A_CONTROL (0x2380a4)
#define CSI2_HUB_GPREG_SIP1_CSI_RX_B_CONTROL (0x2380d0)

#define CSI2_SIP_TOP_CSI_RX_BASE(sip) (0x23805c + (sip) * 0x48)
#define CSI2_SIP_TOP_CSI_RX_PORT_BASE_0(port) (0x23805c + ((port) / 2) * 0x48)
#define CSI2_SIP_TOP_CSI_RX_PORT_BASE_1(port) (0x238088 + ((port) / 2) * 0x48)

/* offset from port base */
#define CSI2_SIP_TOP_CSI_RX_PORT_CONTROL (0x0)
#define CSI2_SIP_TOP_CSI_RX_DLY_CNT_TERMEN_CLANE (0x4)
#define CSI2_SIP_TOP_CSI_RX_DLY_CNT_SETTLE_CLANE (0x8)
#define CSI2_SIP_TOP_CSI_RX_DLY_CNT_TERMEN_DLANE(lane) (0xc + (lane) * 8)
#define CSI2_SIP_TOP_CSI_RX_DLY_CNT_SETTLE_DLANE(lane) (0x10 + (lane) * 8)

#endif /* IPU6_ISYS_CSI2_REG_H */
18 changes: 18 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu-platform-isys.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2020 Intel Corporation */

#ifndef IPU_PLATFORM_ISYS_H
#define IPU_PLATFORM_ISYS_H

#define IPU_ISYS_ENTITY_PREFIX "Intel IPU6"

/*
* FW support max 16 streams
*/
#define IPU_ISYS_MAX_STREAMS 16

#define ISYS_UNISPART_IRQS (IPU_ISYS_UNISPART_IRQ_SW | \
IPU_ISYS_UNISPART_IRQ_CSI0 | \
IPU_ISYS_UNISPART_IRQ_CSI1)

#endif
77 changes: 77 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu-platform-psys.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2020 Intel Corporation */

#ifndef IPU_PLATFORM_PSYS_H
#define IPU_PLATFORM_PSYS_H

#include "ipu-psys.h"
#include <uapi/linux/ipu-psys.h>

#define IPU_PSYS_BUF_SET_POOL_SIZE 8
#define IPU_PSYS_BUF_SET_MAX_SIZE 1024

struct ipu_fw_psys_buffer_set;

enum ipu_psys_cmd_state {
KCMD_STATE_PPG_NEW,
KCMD_STATE_PPG_START,
KCMD_STATE_PPG_ENQUEUE,
KCMD_STATE_PPG_STOP,
KCMD_STATE_PPG_COMPLETE
};

struct ipu_psys_scheduler {
struct list_head ppgs;
struct mutex bs_mutex; /* Protects buf_set field */
struct list_head buf_sets;
};

enum ipu_psys_ppg_state {
PPG_STATE_START = (1 << 0),
PPG_STATE_STARTING = (1 << 1),
PPG_STATE_STARTED = (1 << 2),
PPG_STATE_RUNNING = (1 << 3),
PPG_STATE_SUSPEND = (1 << 4),
PPG_STATE_SUSPENDING = (1 << 5),
PPG_STATE_SUSPENDED = (1 << 6),
PPG_STATE_RESUME = (1 << 7),
PPG_STATE_RESUMING = (1 << 8),
PPG_STATE_RESUMED = (1 << 9),
PPG_STATE_STOP = (1 << 10),
PPG_STATE_STOPPING = (1 << 11),
PPG_STATE_STOPPED = (1 << 12),
};

struct ipu_psys_ppg {
struct ipu_psys_pg *kpg;
struct ipu_psys_fh *fh;
struct list_head list;
struct list_head sched_list;
u64 token;
void *manifest;
struct mutex mutex; /* Protects kcmd and ppg state field */
struct list_head kcmds_new_list;
struct list_head kcmds_processing_list;
struct list_head kcmds_finished_list;
enum ipu_psys_ppg_state state;
u32 pri_base;
int pri_dynamic;
};

struct ipu_psys_buffer_set {
struct list_head list;
struct ipu_fw_psys_buffer_set *buf_set;
size_t size;
size_t buf_set_size;
dma_addr_t dma_addr;
void *kaddr;
struct ipu_psys_kcmd *kcmd;
};

int ipu_psys_kcmd_start(struct ipu_psys *psys, struct ipu_psys_kcmd *kcmd);
void ipu_psys_kcmd_complete(struct ipu_psys *psys, struct ipu_psys_kcmd *kcmd,
int error);
int ipu_psys_fh_init(struct ipu_psys_fh *fh);
int ipu_psys_fh_deinit(struct ipu_psys_fh *fh);

#endif /* IPU_PLATFORM_PSYS_H */
333 changes: 333 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu-platform-regs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2018 - 2020 Intel Corporation */

#ifndef IPU_PLATFORM_REGS_H
#define IPU_PLATFORM_REGS_H

/*
* IPU6 uses uniform address within IPU, therefore all subsystem registers
* locates in one signle space starts from 0 but in different sctions with
* with different addresses, the subsystem offsets are defined to 0 as the
* register definition will have the address offset to 0.
*/
#define IPU_UNIFIED_OFFSET 0

#define IPU_ISYS_IOMMU0_OFFSET 0x2E0000
#define IPU_ISYS_IOMMU1_OFFSET 0x2E0500
#define IPU_ISYS_IOMMUI_OFFSET 0x2E0A00

#define IPU_PSYS_IOMMU0_OFFSET 0x1B0000
#define IPU_PSYS_IOMMU1_OFFSET 0x1B0700
#define IPU_PSYS_IOMMU1R_OFFSET 0x1B0E00
#define IPU_PSYS_IOMMUI_OFFSET 0x1B1500

/* the offset from IOMMU base register */
#define IPU_MMU_L1_STREAM_ID_REG_OFFSET 0x0c
#define IPU_MMU_L2_STREAM_ID_REG_OFFSET 0x4c
#define IPU_PSYS_MMU1W_L2_STREAM_ID_REG_OFFSET 0x8c

#define IPU_MMU_INFO_OFFSET 0x8

#define IPU_ISYS_SPC_OFFSET 0x210000

#define IPU6SE_PSYS_SPC_OFFSET 0x110000
#define IPU6_PSYS_SPC_OFFSET 0x118000

#define IPU_ISYS_DMEM_OFFSET 0x200000
#define IPU_PSYS_DMEM_OFFSET 0x100000

#define IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_EDGE 0x238200
#define IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_MASK 0x238204
#define IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS 0x238208
#define IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR 0x23820c
#define IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_ENABLE 0x238210
#define IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE 0x238214

#define IPU_REG_ISYS_CSI_TOP_CTRL1_IRQ_EDGE 0x238220
#define IPU_REG_ISYS_CSI_TOP_CTRL1_IRQ_MASK 0x238224
#define IPU_REG_ISYS_CSI_TOP_CTRL1_IRQ_STATUS 0x238228
#define IPU_REG_ISYS_CSI_TOP_CTRL1_IRQ_CLEAR 0x23822c
#define IPU_REG_ISYS_CSI_TOP_CTRL1_IRQ_ENABLE 0x238230
#define IPU_REG_ISYS_CSI_TOP_CTRL1_IRQ_LEVEL_NOT_PULSE 0x238234

#define IPU_REG_ISYS_UNISPART_IRQ_EDGE 0x27c000
#define IPU_REG_ISYS_UNISPART_IRQ_MASK 0x27c004
#define IPU_REG_ISYS_UNISPART_IRQ_STATUS 0x27c008
#define IPU_REG_ISYS_UNISPART_IRQ_CLEAR 0x27c00c
#define IPU_REG_ISYS_UNISPART_IRQ_ENABLE 0x27c010
#define IPU_REG_ISYS_UNISPART_IRQ_LEVEL_NOT_PULSE 0x27c014
#define IPU_REG_ISYS_UNISPART_SW_IRQ_REG 0x27c414
#define IPU_REG_ISYS_UNISPART_SW_IRQ_MUX_REG 0x27c418
#define IPU_ISYS_UNISPART_IRQ_CSI0 BIT(2)
#define IPU_ISYS_UNISPART_IRQ_CSI1 BIT(3)
#define IPU_ISYS_UNISPART_IRQ_SW BIT(22)

#define IPU_REG_ISYS_ISL_TOP_IRQ_EDGE 0x2b0200
#define IPU_REG_ISYS_ISL_TOP_IRQ_MASK 0x2b0204
#define IPU_REG_ISYS_ISL_TOP_IRQ_STATUS 0x2b0208
#define IPU_REG_ISYS_ISL_TOP_IRQ_CLEAR 0x2b020c
#define IPU_REG_ISYS_ISL_TOP_IRQ_ENABLE 0x2b0210
#define IPU_REG_ISYS_ISL_TOP_IRQ_LEVEL_NOT_PULSE 0x2b0214

#define IPU_REG_ISYS_CMPR_TOP_IRQ_EDGE 0x2d2100
#define IPU_REG_ISYS_CMPR_TOP_IRQ_MASK 0x2d2104
#define IPU_REG_ISYS_CMPR_TOP_IRQ_STATUS 0x2d2108
#define IPU_REG_ISYS_CMPR_TOP_IRQ_CLEAR 0x2d210c
#define IPU_REG_ISYS_CMPR_TOP_IRQ_ENABLE 0x2d2110
#define IPU_REG_ISYS_CMPR_TOP_IRQ_LEVEL_NOT_PULSE 0x2d2114

/* CDC Burst collector thresholds for isys - 3 FIFOs i = 0..2 */
#define IPU_REG_ISYS_CDC_THRESHOLD(i) (0x27c400 + ((i) * 4))

#define IPU_ISYS_CSI_PHY_NUM 2
#define IPU_CSI_IRQ_NUM_PER_PIPE 4
#define IPU6SE_ISYS_CSI_PORT_NUM 4
#define IPU6_ISYS_CSI_PORT_NUM 8

#define IPU_ISYS_CSI_PORT_IRQ(irq_num) (1 << (irq_num))

/* PSYS Info bits*/
#define IPU_REG_PSYS_INFO_SEG_CMEM_MASTER(a) (0x2C + ((a) * 12))
#define IPU_REG_PSYS_INFO_SEG_XMEM_MASTER(a) (0x5C + ((a) * 12))

/* PKG DIR OFFSET in IMR in secure mode */
#define IPU_PKG_DIR_IMR_OFFSET 0x40

#define IPU_ISYS_REG_SPC_STATUS_CTRL 0x0

#define IPU_ISYS_SPC_STATUS_START BIT(1)
#define IPU_ISYS_SPC_STATUS_RUN BIT(3)
#define IPU_ISYS_SPC_STATUS_READY BIT(5)
#define IPU_ISYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE BIT(12)
#define IPU_ISYS_SPC_STATUS_ICACHE_PREFETCH BIT(13)

#define IPU_PSYS_REG_SPC_STATUS_CTRL 0x0
#define IPU_PSYS_REG_SPC_START_PC 0x4
#define IPU_PSYS_REG_SPC_ICACHE_BASE 0x10
#define IPU_REG_PSYS_INFO_SEG_0_CONFIG_ICACHE_MASTER 0x14

#define IPU_PSYS_SPC_STATUS_START BIT(1)
#define IPU_PSYS_SPC_STATUS_RUN BIT(3)
#define IPU_PSYS_SPC_STATUS_READY BIT(5)
#define IPU_PSYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE BIT(12)
#define IPU_PSYS_SPC_STATUS_ICACHE_PREFETCH BIT(13)

#define IPU_PSYS_REG_SPP0_STATUS_CTRL 0x20000

#define IPU_INFO_ENABLE_SNOOP BIT(0)
#define IPU_INFO_DEC_FORCE_FLUSH BIT(1)
#define IPU_INFO_DEC_PASS_THRU BIT(2)
#define IPU_INFO_ZLW BIT(3)
#define IPU_INFO_STREAM_ID_SET(id) (((id) & 0x1F) << 4)
#define IPU_INFO_REQUEST_DESTINATION_IOSF BIT(9)
#define IPU_INFO_IMR_BASE BIT(10)
#define IPU_INFO_IMR_DESTINED BIT(11)

#define IPU_INFO_REQUEST_DESTINATION_PRIMARY IPU_INFO_REQUEST_DESTINATION_IOSF

/* Trace unit related register definitions */
#define TRACE_REG_MAX_ISYS_OFFSET 0xfffff
#define TRACE_REG_MAX_PSYS_OFFSET 0xfffff
#define IPU_ISYS_OFFSET IPU_ISYS_DMEM_OFFSET
#define IPU_PSYS_OFFSET IPU_PSYS_DMEM_OFFSET
/* ISYS trace unit registers */
/* Trace unit base offset */
#define IPU_TRACE_REG_IS_TRACE_UNIT_BASE 0x27d000
/* Trace monitors */
#define IPU_TRACE_REG_IS_SP_EVQ_BASE 0x211000
/* GPC blocks */
#define IPU_TRACE_REG_IS_SP_GPC_BASE 0x210800
#define IPU_TRACE_REG_IS_ISL_GPC_BASE 0x2b0a00
#define IPU_TRACE_REG_IS_MMU_GPC_BASE 0x2e0f00
/* each CSI2 port has a dedicated trace monitor, index 0..7 */
#define IPU_TRACE_REG_CSI2_TM_BASE(port) (0x220400 + 0x1000 * (port))

/* Trace timers */
#define IPU_TRACE_REG_IS_GPREG_TRACE_TIMER_RST_N 0x27c410
#define TRACE_REG_GPREG_TRACE_TIMER_RST_OFF BIT(0)

/* SIG2CIO */
#define IPU_TRACE_REG_CSI2_PORT_SIG2SIO_GR_BASE(port) \
(0x220e00 + (port) * 0x1000)

/* PSYS trace unit registers */
/* Trace unit base offset */
#define IPU_TRACE_REG_PS_TRACE_UNIT_BASE 0x1b4000
/* Trace monitors */
#define IPU_TRACE_REG_PS_SPC_EVQ_BASE 0x119000
#define IPU_TRACE_REG_PS_SPP0_EVQ_BASE 0x139000

/* GPC blocks */
#define IPU_TRACE_REG_PS_SPC_GPC_BASE 0x118800
#define IPU_TRACE_REG_PS_SPP0_GPC_BASE 0x138800
#define IPU_TRACE_REG_PS_MMU_GPC_BASE 0x1b1b00

/* Trace timers */
#define IPU_TRACE_REG_PS_GPREG_TRACE_TIMER_RST_N 0x1aa714

/*
* s2m_pixel_soc_pixel_remapping is dedicated for the enableing of the
* pixel s2m remp ability.Remap here means that s2m rearange the order
* of the pixels in each 4 pixels group.
* For examle, mirroring remping means that if input's 4 first pixels
* are 1 2 3 4 then in output we should see 4 3 2 1 in this 4 first pixels.
* 0xE4 is from s2m MAS document. It means no remaping.
*/
#define S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING 0xE4
/*
* csi_be_soc_pixel_remapping is for the enabling of the csi\mipi be pixel
* remapping feature. This remapping is exactly like the stream2mmio remapping.
*/
#define CSI_BE_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING 0xE4

#define IPU_REG_DMA_TOP_AB_GROUP1_BASE_ADDR 0x1AE000
#define IPU_REG_DMA_TOP_AB_GROUP2_BASE_ADDR 0x1AF000
#define IPU_REG_DMA_TOP_AB_RING_MIN_OFFSET(n) (0x4 + (n) * 0xC)
#define IPU_REG_DMA_TOP_AB_RING_MAX_OFFSET(n) (0x8 + (n) * 0xC)
#define IPU_REG_DMA_TOP_AB_RING_ACCESS_OFFSET(n) (0xC + (n) * 0xC)

enum ipu_device_ab_group1_target_id {
IPU_DEVICE_AB_GROUP1_TARGET_ID_R0_SPC_DMEM,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R1_SPC_DMEM,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R2_SPC_DMEM,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R3_SPC_STATUS_REG,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R4_SPC_MASTER_BASE_ADDR,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R5_SPC_PC_STALL,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R6_SPC_EQ,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R7_SPC_RESERVED,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R8_SPC_RESERVED,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R9_SPP0,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R10_SPP1,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R11_CENTRAL_R1,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R12_IRQ,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R13_CENTRAL_R2,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R14_DMA,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R15_DMA,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R16_GP,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R17_ZLW_INSERTER,
IPU_DEVICE_AB_GROUP1_TARGET_ID_R18_AB,
};

enum nci_ab_access_mode {
NCI_AB_ACCESS_MODE_RW, /* read & write */
NCI_AB_ACCESS_MODE_RO, /* read only */
NCI_AB_ACCESS_MODE_WO, /* write only */
NCI_AB_ACCESS_MODE_NA /* No access at all */
};

/*
* 3:0 CSI_PORT.irq_out[3:0] CSI_PORT_CTRL0 IRQ outputs (4bits)
* [0] CSI_PORT.IRQ_CTRL0_csi
* [1] CSI_PORT.IRQ_CTRL1_csi_sync
* [2] CSI_PORT.IRQ_CTRL2_s2m_sids0to7
* [3] CSI_PORT.IRQ_CTRL3_s2m_sids8to15
*/
#define IPU_ISYS_UNISPART_IRQ_CSI2(port) \
(0x3 << ((port) * IPU_CSI_IRQ_NUM_PER_PIPE))

/* IRQ-related registers in PSYS */
#define IPU_REG_PSYS_GPDEV_IRQ_EDGE 0x1aa200
#define IPU_REG_PSYS_GPDEV_IRQ_MASK 0x1aa204
#define IPU_REG_PSYS_GPDEV_IRQ_STATUS 0x1aa208
#define IPU_REG_PSYS_GPDEV_IRQ_CLEAR 0x1aa20c
#define IPU_REG_PSYS_GPDEV_IRQ_ENABLE 0x1aa210
#define IPU_REG_PSYS_GPDEV_IRQ_LEVEL_NOT_PULSE 0x1aa214
/* There are 8 FW interrupts, n = 0..7 */
#define IPU_PSYS_GPDEV_FWIRQ0 5
#define IPU_PSYS_GPDEV_FWIRQ1 6
#define IPU_PSYS_GPDEV_FWIRQ2 7
#define IPU_PSYS_GPDEV_FWIRQ3 8
#define IPU_PSYS_GPDEV_FWIRQ4 9
#define IPU_PSYS_GPDEV_FWIRQ5 10
#define IPU_PSYS_GPDEV_FWIRQ6 11
#define IPU_PSYS_GPDEV_FWIRQ7 12
#define IPU_PSYS_GPDEV_IRQ_FWIRQ(n) (1 << (n))
#define IPU_REG_PSYS_GPDEV_FWIRQ(n) (4 * (n) + 0x1aa100)

/*
* ISYS GPC (Gerneral Performance Counters) Registers
*/
#define IPU_ISYS_GPC_BASE 0x2E0000
#define IPU_ISYS_GPREG_TRACE_TIMER_RST 0x27C410
enum ipu_isf_cdc_mmu_gpc_registers {
IPU_ISF_CDC_MMU_GPC_SOFT_RESET = 0x0F00,
IPU_ISF_CDC_MMU_GPC_OVERALL_ENABLE = 0x0F04,
IPU_ISF_CDC_MMU_GPC_ENABLE0 = 0x0F20,
IPU_ISF_CDC_MMU_GPC_VALUE0 = 0x0F60,
IPU_ISF_CDC_MMU_GPC_CNT_SEL0 = 0x0FA0,
};

/*
* GPC (Gerneral Performance Counters) Registers
*/
#define IPU_GPC_BASE 0x1B0000
#define IPU_GPREG_TRACE_TIMER_RST 0x1AA714
enum ipu_cdc_mmu_gpc_registers {
IPU_CDC_MMU_GPC_SOFT_RESET = 0x1B00,
IPU_CDC_MMU_GPC_OVERALL_ENABLE = 0x1B04,
IPU_CDC_MMU_GPC_TRACE_HEADER = 0x1B08,
IPU_CDC_MMU_GPC_TRACE_ADDR = 0x1B0C,
IPU_CDC_MMU_GPC_TRACE_ENABLE_NPK = 0x1B10,
IPU_CDC_MMU_GPC_TRACE_ENABLE_DDR = 0x1B14,
IPU_CDC_MMU_GPC_LP_CLEAR = 0x1B18,
IPU_CDC_MMU_GPC_LOST_PACKET = 0x1B1C,
IPU_CDC_MMU_GPC_ENABLE0 = 0x1B20,
IPU_CDC_MMU_GPC_VALUE0 = 0x1B60,
IPU_CDC_MMU_GPC_CNT_SEL0 = 0x1BA0,
IPU_CDC_MMU_GPC_START_SEL0 = 0x1BE0,
IPU_CDC_MMU_GPC_STOP_SEL0 = 0x1C20,
IPU_CDC_MMU_GPC_MSG_SEL0 = 0x1C60,
IPU_CDC_MMU_GPC_PLOAD_SEL0 = 0x1CA0,
IPU_CDC_MMU_GPC_IRQ_TRIGGER_VALUE0 = 0x1CE0,
IPU_CDC_MMU_GPC_IRQ_TIMER_SEL0 = 0x1D20,
IPU_CDC_MMU_GPC_IRQ_ENABLE0 = 0x1D60,
IPU_CDC_MMU_GPC_END = 0x1D9C
};

#define IPU_GPC_SENSE_OFFSET 7
#define IPU_GPC_ROUTE_OFFSET 5
#define IPU_GPC_SOURCE_OFFSET 0

/*
* Signals monitored by GPC
*/
#define IPU_GPC_TRACE_TLB_MISS_MMU_LB_IDX 0
#define IPU_GPC_TRACE_FULL_WRITE_LB_IDX 1
#define IPU_GPC_TRACE_NOFULL_WRITE_LB_IDX 2
#define IPU_GPC_TRACE_FULL_READ_LB_IDX 3
#define IPU_GPC_TRACE_NOFULL_READ_LB_IDX 4
#define IPU_GPC_TRACE_STALL_LB_IDX 5
#define IPU_GPC_TRACE_ZLW_LB_IDX 6
#define IPU_GPC_TRACE_TLB_MISS_MMU_HBTX_IDX 7
#define IPU_GPC_TRACE_FULL_WRITE_HBTX_IDX 8
#define IPU_GPC_TRACE_NOFULL_WRITE_HBTX_IDX 9
#define IPU_GPC_TRACE_FULL_READ_HBTX_IDX 10
#define IPU_GPC_TRACE_STALL_HBTX_IDX 11
#define IPU_GPC_TRACE_ZLW_HBTX_IDX 12
#define IPU_GPC_TRACE_TLB_MISS_MMU_HBFRX_IDX 13
#define IPU_GPC_TRACE_FULL_READ_HBFRX_IDX 14
#define IPU_GPC_TRACE_NOFULL_READ_HBFRX_IDX 15
#define IPU_GPC_TRACE_STALL_HBFRX_IDX 16
#define IPU_GPC_TRACE_ZLW_HBFRX_IDX 17
#define IPU_GPC_TRACE_TLB_MISS_ICACHE_IDX 18
#define IPU_GPC_TRACE_FULL_READ_ICACHE_IDX 19
#define IPU_GPC_TRACE_STALL_ICACHE_IDX 20
/*
* psys subdomains power request regs
*/
enum ipu_device_buttress_psys_domain_pos {
IPU_PSYS_SUBDOMAIN_ISA = 0,
IPU_PSYS_SUBDOMAIN_PSA = 1,
IPU_PSYS_SUBDOMAIN_BB = 2,
IPU_PSYS_SUBDOMAIN_IDSP1 = 3, /* only in IPU6M */
IPU_PSYS_SUBDOMAIN_IDSP2 = 4, /* only in IPU6M */
};

#define IPU_PSYS_SUBDOMAINS_POWER_MASK (BIT(IPU_PSYS_SUBDOMAIN_ISA) | \
BIT(IPU_PSYS_SUBDOMAIN_PSA) | \
BIT(IPU_PSYS_SUBDOMAIN_BB))

#define IPU_PSYS_SUBDOMAINS_POWER_REQ 0xa0
#define IPU_PSYS_SUBDOMAINS_POWER_STATUS 0xa4

#endif /* IPU_PLATFORM_REGS_H */
98 changes: 98 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu-platform-resources.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2018 - 2020 Intel Corporation */

#ifndef IPU_PLATFORM_RESOURCES_COMMON_H
#define IPU_PLATFORM_RESOURCES_COMMON_H

#define IPU_FW_PSYS_N_PADDING_UINT8_IN_PROGRAM_MANIFEST 0

#define IPU_FW_PSYS_N_PADDING_UINT8_IN_PROCESS_STRUCT 0
#define IPU_FW_PSYS_N_PADDING_UINT8_IN_PROCESS_GROUP_STRUCT 2
#define IPU_FW_PSYS_N_PADDING_UINT8_IN_PROGRAM_MANIFEST_EXT 2

#define IPU_FW_PSYS_N_PADDING_UINT8_IN_TERMINAL_STRUCT 5

#define IPU_FW_PSYS_N_PADDING_UINT8_IN_PARAM_TERMINAL_STRUCT 6

#define IPU_FW_PSYS_N_PADDING_UINT8_IN_DATA_TERMINAL_STRUCT 3

#define IPU_FW_PSYS_N_PADDING_UINT8_IN_FRAME_DESC_STRUCT 3
#define IPU_FW_PSYS_N_FRAME_PLANES 6
#define IPU_FW_PSYS_N_PADDING_UINT8_IN_FRAME_STRUCT 4

#define IPU_FW_PSYS_N_PADDING_UINT8_IN_BUFFER_SET_STRUCT 1

#define IPU_FW_PSYS_MAX_INPUT_DEC_RESOURCES 4
#define IPU_FW_PSYS_MAX_OUTPUT_DEC_RESOURCES 4

#define IPU_FW_PSYS_PROCESS_MAX_CELLS 1
#define IPU_FW_PSYS_KERNEL_BITMAP_NOF_ELEMS 4
#define IPU_FW_PSYS_RBM_NOF_ELEMS 5
#define IPU_FW_PSYS_KBM_NOF_ELEMS 4

struct ipu_fw_psys_process {
s16 parent_offset;
u8 size;
u8 cell_dependencies_offset;
u8 terminal_dependencies_offset;
u8 process_extension_offset;
u8 ID;
u8 program_idx;
u8 state;
u8 cells[IPU_FW_PSYS_PROCESS_MAX_CELLS];
u8 cell_dependency_count;
u8 terminal_dependency_count;
};

struct ipu_fw_psys_program_manifest {
u32 kernel_bitmap[IPU_FW_PSYS_KERNEL_BITMAP_NOF_ELEMS];
s16 parent_offset;
u8 program_dependency_offset;
u8 terminal_dependency_offset;
u8 size;
u8 program_extension_offset;
u8 program_type;
u8 ID;
u8 cells[IPU_FW_PSYS_PROCESS_MAX_CELLS];
u8 cell_type_id;
u8 program_dependency_count;
u8 terminal_dependency_count;
};

/* platform specific resource interface */
struct ipu_psys_resource_pool;
struct ipu_psys_resource_alloc;
struct ipu_fw_psys_process_group;
int ipu_psys_allocate_resources(const struct device *dev,
struct ipu_fw_psys_process_group *pg,
void *pg_manifest,
struct ipu_psys_resource_alloc *alloc,
struct ipu_psys_resource_pool *pool);
int ipu_psys_move_resources(const struct device *dev,
struct ipu_psys_resource_alloc *alloc,
struct ipu_psys_resource_pool *source_pool,
struct ipu_psys_resource_pool *target_pool);

void ipu_psys_resource_copy(struct ipu_psys_resource_pool *src,
struct ipu_psys_resource_pool *dest);

int ipu_psys_try_allocate_resources(struct device *dev,
struct ipu_fw_psys_process_group *pg,
void *pg_manifest,
struct ipu_psys_resource_pool *pool);

void ipu_psys_free_resources(struct ipu_psys_resource_alloc *alloc,
struct ipu_psys_resource_pool *pool);

int ipu_fw_psys_set_proc_dfm_bitmap(struct ipu_fw_psys_process *ptr,
u16 id, u32 bitmap,
u32 active_bitmap);

int ipu_psys_allocate_cmd_queue_resource(struct ipu_psys_resource_pool *pool);
void ipu_psys_free_cmd_queue_resource(struct ipu_psys_resource_pool *pool,
u8 queue_id);

extern const struct ipu_fw_resource_definitions *ipu6_res_defs;
extern const struct ipu_fw_resource_definitions *ipu6se_res_defs;
extern struct ipu6_psys_hw_res_variant hw_var;
#endif /* IPU_PLATFORM_RESOURCES_COMMON_H */
33 changes: 33 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu-platform.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2013 - 2020 Intel Corporation */

#ifndef IPU_PLATFORM_H
#define IPU_PLATFORM_H

#define IPU_NAME "intel-ipu6"

#define IPU6SE_FIRMWARE_NAME "intel/ipu6se_fw.bin"
#define IPU6_FIRMWARE_NAME "intel/ipu6_fw.bin"

/*
* The following definitions are encoded to the media_device's model field so
* that the software components which uses IPU driver can get the hw stepping
* information.
*/
#define IPU_MEDIA_DEV_MODEL_NAME "ipu6"

#define IPU6SE_ISYS_NUM_STREAMS 8 /* Max 8 */
#define IPU6_ISYS_NUM_STREAMS 16 /* Max 16 */

/* declearations, definitions in ipu6.c */
extern struct ipu_isys_internal_pdata isys_ipdata;
extern struct ipu_psys_internal_pdata psys_ipdata;
extern const struct ipu_buttress_ctrl isys_buttress_ctrl;
extern const struct ipu_buttress_ctrl psys_buttress_ctrl;

/* definitions in ipu6-isys.c */
extern struct ipu_trace_block isys_trace_blocks[];
/* definitions in ipu6-psys.c */
extern struct ipu_trace_block psys_trace_blocks[];

#endif
839 changes: 839 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu-resources.c

Large diffs are not rendered by default.

626 changes: 626 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu6-fw-resources.c

Large diffs are not rendered by default.

526 changes: 526 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2020 Intel Corporation */

#ifndef IPU6_ISYS_CSI2_H
#define IPU6_ISYS_CSI2_H

struct ipu_isys_csi2_timing;
struct ipu_isys_csi2;
struct ipu_isys_pipeline;
struct v4l2_subdev;

#define IPU_ISYS_SHORT_PACKET_DTYPE_MASK 0x3f

#endif /* IPU6_ISYS_CSI2_H */
211 changes: 211 additions & 0 deletions drivers/media/pci/intel/ipu6/ipu6-isys-gpc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020 Intel Corporation

#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/pm_runtime.h>

#include "ipu-isys.h"
#include "ipu-platform-regs.h"

#define IPU_ISYS_GPC_NUM 16

#ifndef CONFIG_PM
#define pm_runtime_get_sync(d) 0
#define pm_runtime_put(d) 0
#endif

struct ipu_isys_gpc {
bool enable;
unsigned int route;
unsigned int source;
unsigned int sense;
unsigned int gpcindex;
void *prit;
};

struct ipu_isys_gpcs {
bool gpc_enable;
struct ipu_isys_gpc gpc[IPU_ISYS_GPC_NUM];
void *prit;
};

static int ipu6_isys_gpc_global_enable_get(void *data, u64 *val)
{
struct ipu_isys_gpcs *isys_gpcs = data;
struct ipu_isys *isys = isys_gpcs->prit;

mutex_lock(&isys->mutex);

*val = isys_gpcs->gpc_enable;

mutex_unlock(&isys->mutex);
return 0;
}

static int ipu6_isys_gpc_global_enable_set(void *data, u64 val)
{
struct ipu_isys_gpcs *isys_gpcs = data;
struct ipu_isys *isys = isys_gpcs->prit;
void __iomem *base;
int i, ret;

if (val != 0 && val != 1)
return -EINVAL;

if (!isys || !isys->pdata || !isys->pdata->base)
return -EINVAL;

mutex_lock(&isys->mutex);

base = isys->pdata->base + IPU_ISYS_GPC_BASE;

ret = pm_runtime_get_sync(&isys->adev->dev);
if (ret < 0) {
pm_runtime_put(&isys->adev->dev);
mutex_unlock(&isys->mutex);
return ret;
}

if (!val) {
writel(0x0, base + IPU_ISYS_GPREG_TRACE_TIMER_RST);
writel(0x0, base + IPU_ISF_CDC_MMU_GPC_OVERALL_ENABLE);
writel(0xffff, base + IPU_ISF_CDC_MMU_GPC_SOFT_RESET);
isys_gpcs->gpc_enable = false;
for (i = 0; i < IPU_ISYS_GPC_NUM; i++) {
isys_gpcs->gpc[i].enable = 0;
isys_gpcs->gpc[i].sense = 0;
isys_gpcs->gpc[i].route = 0;
isys_gpcs->gpc[i].source = 0;
}
pm_runtime_mark_last_busy(&isys->adev->dev);
pm_runtime_put_autosuspend(&isys->adev->dev);
} else {
/*
* Set gpc reg and start all gpc here.
* RST free running local timer.
*/
writel(0x0, base + IPU_ISYS_GPREG_TRACE_TIMER_RST);
writel(0x1, base + IPU_ISYS_GPREG_TRACE_TIMER_RST);

for (i = 0; i < IPU_ISYS_GPC_NUM; i++) {
/* Enable */
writel(isys_gpcs->gpc[i].enable,
base + IPU_ISF_CDC_MMU_GPC_ENABLE0 + 4 * i);
/* Setting (route/source/sense) */
writel((isys_gpcs->gpc[i].sense
<< IPU_GPC_SENSE_OFFSET)
+ (isys_gpcs->gpc[i].route
<< IPU_GPC_ROUTE_OFFSET)
+ (isys_gpcs->gpc[i].source
<< IPU_GPC_SOURCE_OFFSET),
base + IPU_ISF_CDC_MMU_GPC_CNT_SEL0 + 4 * i);
}

/* Soft reset and Overall Enable. */
writel(0x0, base + IPU_ISF_CDC_MMU_GPC_OVERALL_ENABLE);
writel(0xffff, base + IPU_ISF_CDC_MMU_GPC_SOFT_RESET);
writel(0x1, base + IPU_ISF_CDC_MMU_GPC_OVERALL_ENABLE);

isys_gpcs->gpc_enable = true;
}

mutex_unlock(&isys->mutex);
return 0;
}

DEFINE_SIMPLE_ATTRIBUTE(isys_gpc_globe_enable_fops,
ipu6_isys_gpc_global_enable_get,
ipu6_isys_gpc_global_enable_set, "%llu\n");

static int ipu6_isys_gpc_count_get(void *data, u64 *val)
{
struct ipu_isys_gpc *isys_gpc = data;
struct ipu_isys *isys = isys_gpc->prit;
void __iomem *base;

if (!isys || !isys->pdata || !isys->pdata->base)
return -EINVAL;

spin_lock(&isys->power_lock);
if (isys->power) {
base = isys->pdata->base + IPU_ISYS_GPC_BASE;
*val = readl(base + IPU_ISF_CDC_MMU_GPC_VALUE0
+ 4 * isys_gpc->gpcindex);
} else {
*val = 0;
}
spin_unlock(&isys->power_lock);

return 0;
}

DEFINE_SIMPLE_ATTRIBUTE(isys_gpc_count_fops, ipu6_isys_gpc_count_get,
NULL, "%llu\n");

int ipu_isys_gpc_init_debugfs(struct ipu_isys *isys)
{
struct dentry *gpcdir;
struct dentry *dir;
struct dentry *file;
int i;
char gpcname[10];
struct ipu_isys_gpcs *isys_gpcs;

isys_gpcs = devm_kzalloc(&isys->adev->dev, sizeof(*isys_gpcs),
GFP_KERNEL);
if (!isys_gpcs)
return -ENOMEM;

gpcdir = debugfs_create_dir("gpcs", isys->debugfsdir);
if (IS_ERR(gpcdir))
return -ENOMEM;

isys_gpcs->prit = isys;
file = debugfs_create_file("enable", 0600, gpcdir, isys_gpcs,
&isys_gpc_globe_enable_fops);
if (IS_ERR(file))
goto err;

for (i = 0; i < IPU_ISYS_GPC_NUM; i++) {
sprintf(gpcname, "gpc%d", i);
dir = debugfs_create_dir(gpcname, gpcdir);
if (IS_ERR(dir))
goto err;

file = debugfs_create_bool("enable", 0600, dir,
&isys_gpcs->gpc[i].enable);
if (IS_ERR(file))
goto err;

file = debugfs_create_u32("source", 0600, dir,
&isys_gpcs->gpc[i].source);
if (IS_ERR(file))
goto err;

file = debugfs_create_u32("route", 0600, dir,
&isys_gpcs->gpc[i].route);
if (IS_ERR(file))
goto err;

file = debugfs_create_u32("sense", 0600, dir,
&isys_gpcs->gpc[i].sense);
if (IS_ERR(file))
goto err;

isys_gpcs->gpc[i].gpcindex = i;
isys_gpcs->gpc[i].prit = isys;
file = debugfs_create_file("count", 0400, dir,
&isys_gpcs->gpc[i],
&isys_gpc_count_fops);
if (IS_ERR(file))
goto err;
}

return 0;

err:
debugfs_remove_recursive(gpcdir);
return -ENOMEM;
}
#endif
Loading