diff options
Diffstat (limited to 'drivers/staging')
164 files changed, 17215 insertions, 6060 deletions
diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c index 351f983ef9149..57ed58065ebac 100644 --- a/drivers/staging/axis-fifo/axis-fifo.c +++ b/drivers/staging/axis-fifo/axis-fifo.c @@ -33,6 +33,7 @@ #include <linux/uaccess.h> #include <linux/jiffies.h> #include <linux/miscdevice.h> +#include <linux/debugfs.h> /* ---------------------------- * driver parameters @@ -44,6 +45,8 @@ #define READ_BUF_SIZE 128U /* read buffer length in words */ #define WRITE_BUF_SIZE 128U /* write buffer length in words */ +#define AXIS_FIFO_DEBUG_REG_NAME_MAX_LEN 4 + /* ---------------------------- * IP register offsets * ---------------------------- @@ -137,180 +140,13 @@ struct axis_fifo { struct device *dt_device; /* device created from the device tree */ struct miscdevice miscdev; -}; - -/* ---------------------------- - * sysfs entries - * ---------------------------- - */ - -static ssize_t sysfs_write(struct device *dev, const char *buf, - size_t count, unsigned int addr_offset) -{ - struct axis_fifo *fifo = dev_get_drvdata(dev); - unsigned long tmp; - int rc; - - rc = kstrtoul(buf, 0, &tmp); - if (rc < 0) - return rc; - - iowrite32(tmp, fifo->base_addr + addr_offset); - - return count; -} - -static ssize_t sysfs_read(struct device *dev, char *buf, - unsigned int addr_offset) -{ - struct axis_fifo *fifo = dev_get_drvdata(dev); - unsigned int read_val; - - read_val = ioread32(fifo->base_addr + addr_offset); - return sysfs_emit(buf, "0x%x\n", read_val); -} - -static ssize_t isr_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return sysfs_write(dev, buf, count, XLLF_ISR_OFFSET); -} - -static ssize_t isr_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_read(dev, buf, XLLF_ISR_OFFSET); -} - -static DEVICE_ATTR_RW(isr); - -static ssize_t ier_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return sysfs_write(dev, buf, count, XLLF_IER_OFFSET); -} - -static ssize_t ier_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_read(dev, buf, XLLF_IER_OFFSET); -} - -static DEVICE_ATTR_RW(ier); - -static ssize_t tdfr_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return sysfs_write(dev, buf, count, XLLF_TDFR_OFFSET); -} - -static DEVICE_ATTR_WO(tdfr); - -static ssize_t tdfv_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_read(dev, buf, XLLF_TDFV_OFFSET); -} - -static DEVICE_ATTR_RO(tdfv); - -static ssize_t tdfd_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return sysfs_write(dev, buf, count, XLLF_TDFD_OFFSET); -} -static DEVICE_ATTR_WO(tdfd); - -static ssize_t tlr_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return sysfs_write(dev, buf, count, XLLF_TLR_OFFSET); -} - -static DEVICE_ATTR_WO(tlr); - -static ssize_t rdfr_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return sysfs_write(dev, buf, count, XLLF_RDFR_OFFSET); -} - -static DEVICE_ATTR_WO(rdfr); - -static ssize_t rdfo_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_read(dev, buf, XLLF_RDFO_OFFSET); -} - -static DEVICE_ATTR_RO(rdfo); - -static ssize_t rdfd_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_read(dev, buf, XLLF_RDFD_OFFSET); -} - -static DEVICE_ATTR_RO(rdfd); - -static ssize_t rlr_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_read(dev, buf, XLLF_RLR_OFFSET); -} - -static DEVICE_ATTR_RO(rlr); - -static ssize_t srr_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return sysfs_write(dev, buf, count, XLLF_SRR_OFFSET); -} - -static DEVICE_ATTR_WO(srr); - -static ssize_t tdr_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return sysfs_write(dev, buf, count, XLLF_TDR_OFFSET); -} - -static DEVICE_ATTR_WO(tdr); - -static ssize_t rdr_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sysfs_read(dev, buf, XLLF_RDR_OFFSET); -} - -static DEVICE_ATTR_RO(rdr); - -static struct attribute *axis_fifo_attrs[] = { - &dev_attr_isr.attr, - &dev_attr_ier.attr, - &dev_attr_tdfr.attr, - &dev_attr_tdfv.attr, - &dev_attr_tdfd.attr, - &dev_attr_tlr.attr, - &dev_attr_rdfr.attr, - &dev_attr_rdfo.attr, - &dev_attr_rdfd.attr, - &dev_attr_rlr.attr, - &dev_attr_srr.attr, - &dev_attr_tdr.attr, - &dev_attr_rdr.attr, - NULL, -}; - -static const struct attribute_group axis_fifo_attrs_group = { - .name = "ip_registers", - .attrs = axis_fifo_attrs, + struct dentry *debugfs_dir; }; -static const struct attribute_group *axis_fifo_attrs_groups[] = { - &axis_fifo_attrs_group, - NULL, +struct axis_fifo_debug_reg { + const char * const name; + unsigned int offset; }; /* ---------------------------- @@ -711,6 +547,37 @@ static const struct file_operations fops = { .write = axis_fifo_write }; +static int axis_fifo_debugfs_regs_show(struct seq_file *m, void *p) +{ + static const struct axis_fifo_debug_reg regs[] = { + {"isr", XLLF_ISR_OFFSET}, + {"ier", XLLF_IER_OFFSET}, + {"tdfv", XLLF_TDFV_OFFSET}, + {"rdfo", XLLF_RDFO_OFFSET}, + { /* Sentinel */ }, + }; + const struct axis_fifo_debug_reg *reg; + struct axis_fifo *fifo = m->private; + + for (reg = regs; reg->name; ++reg) { + u32 val = ioread32(fifo->base_addr + reg->offset); + + seq_printf(m, "%*s: 0x%08x\n", AXIS_FIFO_DEBUG_REG_NAME_MAX_LEN, + reg->name, val); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(axis_fifo_debugfs_regs); + +static void axis_fifo_debugfs_init(struct axis_fifo *fifo) +{ + fifo->debugfs_dir = debugfs_create_dir(dev_name(fifo->dt_device), NULL); + + debugfs_create_file("regs", 0444, fifo->debugfs_dir, fifo, + &axis_fifo_debugfs_regs_fops); +} + /* read named property from the device tree */ static int get_dts_property(struct axis_fifo *fifo, char *name, unsigned int *var) @@ -877,12 +744,13 @@ static int axis_fifo_probe(struct platform_device *pdev) fifo->miscdev.fops = &fops; fifo->miscdev.minor = MISC_DYNAMIC_MINOR; fifo->miscdev.name = device_name; - fifo->miscdev.groups = axis_fifo_attrs_groups; fifo->miscdev.parent = dev; rc = misc_register(&fifo->miscdev); if (rc < 0) goto err_initial; + axis_fifo_debugfs_init(fifo); + return 0; err_initial: @@ -895,6 +763,7 @@ static void axis_fifo_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; struct axis_fifo *fifo = dev_get_drvdata(dev); + debugfs_remove(fifo->debugfs_dir); misc_deregister(&fifo->miscdev); dev_set_drvdata(dev, NULL); } diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index da9c64152a606..9e7b84071174c 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -568,18 +568,13 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, height = display->height; } - vmem_size = display->width * display->height * bpp / 8; - vmem = vzalloc(vmem_size); - if (!vmem) - goto alloc_fail; - fbdefio = devm_kzalloc(dev, sizeof(struct fb_deferred_io), GFP_KERNEL); if (!fbdefio) - goto alloc_fail; + return NULL; buf = devm_kzalloc(dev, 128, GFP_KERNEL); if (!buf) - goto alloc_fail; + return NULL; if (display->gamma_num && display->gamma_len) { gamma_curves = devm_kcalloc(dev, @@ -588,12 +583,17 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, sizeof(gamma_curves[0]), GFP_KERNEL); if (!gamma_curves) - goto alloc_fail; + return NULL; } info = framebuffer_alloc(sizeof(struct fbtft_par), dev); if (!info) - goto alloc_fail; + return NULL; + + vmem_size = display->width * display->height * bpp / 8; + vmem = vzalloc(vmem_size); + if (!vmem) + goto release_framebuf; info->screen_buffer = vmem; info->fbops = &fbtft_ops; @@ -612,7 +612,8 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, info->fix.line_length = width * bpp / 8; info->fix.accel = FB_ACCEL_NONE; info->fix.smem_len = vmem_size; - fb_deferred_io_init(info); + if (fb_deferred_io_init(info)) + goto release_screen_buffer; info->var.rotate = pdata->rotate; info->var.xres = width; @@ -652,7 +653,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, if (par->gamma.curves && gamma) { if (fbtft_gamma_parse_str(par, par->gamma.curves, gamma, strlen(gamma))) - goto release_framebuf; + goto cleanup_deferred; } /* Transmit buffer */ @@ -667,9 +668,9 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, #endif if (txbuflen > 0) { - txbuf = devm_kzalloc(par->info->device, txbuflen, GFP_KERNEL); + txbuf = kzalloc(txbuflen, GFP_KERNEL); if (!txbuf) - goto release_framebuf; + goto cleanup_deferred; par->txbuf.buf = txbuf; par->txbuf.len = txbuflen; } @@ -691,12 +692,12 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, return info; +cleanup_deferred: + fb_deferred_io_cleanup(info); +release_screen_buffer: + vfree(info->screen_buffer); release_framebuf: framebuffer_release(info); - -alloc_fail: - vfree(vmem); - return NULL; } EXPORT_SYMBOL(fbtft_framebuffer_alloc); @@ -709,6 +710,9 @@ EXPORT_SYMBOL(fbtft_framebuffer_alloc); */ void fbtft_framebuffer_release(struct fb_info *info) { + struct fbtft_par *par = info->par; + + kfree(par->txbuf.buf); fb_deferred_io_cleanup(info); vfree(info->screen_buffer); framebuffer_release(info); diff --git a/drivers/staging/gpib/TODO b/drivers/staging/gpib/TODO index bf2c397425487..ab41a7f9ca5bf 100644 --- a/drivers/staging/gpib/TODO +++ b/drivers/staging/gpib/TODO @@ -1,6 +1,9 @@ TODO: - checkpatch.pl fixes -- fix device drivers that are broken ("depends on BROKEN" in Kconfig) + These checks should be ignored: + CHECK:ALLOC_SIZEOF_STRUCT: Prefer kmalloc(sizeof(*board->private_data)...) over kmalloc(sizeof(struct xxx_priv)...) + ./gpio/gpib_bitbang.c:50: ERROR:COMPLEX_MACRO: Macros with complex values should be enclosed in parenthese + This warning will be addressed later: WARNING:UNDOCUMENTED_DT_STRING: DT compatible string - tidy-up comments: - there are some "//comments" and "// comments" scattered around - sometimes they are misaligned diff --git a/drivers/staging/gpib/cb7210/cb7210.c b/drivers/staging/gpib/cb7210/cb7210.c index 298ed306189df..3e2397898a9ba 100644 --- a/drivers/staging/gpib/cb7210/cb7210.c +++ b/drivers/staging/gpib/cb7210/cb7210.c @@ -1184,8 +1184,7 @@ struct local_info { static int cb_gpib_probe(struct pcmcia_device *link) { struct local_info *info; - -// int ret, i; + int ret; /* Allocate space for private device-specific data */ info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -1211,8 +1210,16 @@ static int cb_gpib_probe(struct pcmcia_device *link) /* Register with Card Services */ curr_dev = link; - return cb_gpib_config(link); -} /* gpib_attach */ + ret = cb_gpib_config(link); + if (ret) + goto free_info; + + return 0; + +free_info: + kfree(info); + return ret; +} /* * This deletes a driver "instance". The device is de-registered diff --git a/drivers/staging/gpib/cec/cec_gpib.c b/drivers/staging/gpib/cec/cec_gpib.c index e8736cbf50e36..0c9d10ee7cd26 100644 --- a/drivers/staging/gpib/cec/cec_gpib.c +++ b/drivers/staging/gpib/cec/cec_gpib.c @@ -302,7 +302,7 @@ static int cec_pci_attach(struct gpib_board *board, const struct gpib_board_conf return -EBUSY; cec_priv->plx_iobase = pci_resource_start(cec_priv->pci_device, 1); - nec_priv->iobase = pci_resource_start(cec_priv->pci_device, 3); + nec_priv->iobase = pci_resource_start(cec_priv->pci_device, 3); isr_flags |= IRQF_SHARED; if (request_irq(cec_priv->pci_device->irq, cec_interrupt, isr_flags, DRV_NAME, board)) { diff --git a/drivers/staging/gpib/common/gpib_os.c b/drivers/staging/gpib/common/gpib_os.c index a193d64db0337..2a0465ce16c4a 100644 --- a/drivers/staging/gpib/common/gpib_os.c +++ b/drivers/staging/gpib/common/gpib_os.c @@ -610,7 +610,7 @@ int ibclose(struct inode *inode, struct file *filep) long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg) { - unsigned int minor = iminor(filep->f_path.dentry->d_inode); + unsigned int minor = iminor(file_inode(filep)); struct gpib_board *board; struct gpib_file_private *file_priv = filep->private_data; long retval = -ENOTTY; @@ -831,7 +831,7 @@ static int board_type_ioctl(struct gpib_file_private *file_priv, retval = copy_from_user(&cmd, (void __user *)arg, sizeof(struct gpib_board_type_ioctl)); if (retval) - return retval; + return -EFAULT; for (list_ptr = registered_drivers.next; list_ptr != ®istered_drivers; list_ptr = list_ptr->next) { @@ -1774,7 +1774,7 @@ static int query_board_rsv_ioctl(struct gpib_board *board, unsigned long arg) static int board_info_ioctl(const struct gpib_board *board, unsigned long arg) { - struct gpib_board_info_ioctl info; + struct gpib_board_info_ioctl info = { }; int retval; info.pad = board->pad; diff --git a/drivers/staging/gpib/gpio/gpib_bitbang.c b/drivers/staging/gpib/gpio/gpib_bitbang.c index 625fef24a0bfa..17884810fd693 100644 --- a/drivers/staging/gpib/gpio/gpib_bitbang.c +++ b/drivers/staging/gpib/gpio/gpib_bitbang.c @@ -169,7 +169,7 @@ static struct gpio_desc *all_descriptors[GPIB_PINS + SN7516X_PINS]; #define TE all_descriptors[18] #define ACT_LED all_descriptors[19] -/* YOGA dapter uses a global enable for the buffer chips, re-using the TE pin */ +/* YOGA adapter uses a global enable for the buffer chips, re-using the TE pin */ #define YOGA_ENABLE TE static int gpios_vector[] = { diff --git a/drivers/staging/gpib/hp_82341/hp_82341.c b/drivers/staging/gpib/hp_82341/hp_82341.c index 1b0822b2a3b8e..e5c1997ce7d9c 100644 --- a/drivers/staging/gpib/hp_82341/hp_82341.c +++ b/drivers/staging/gpib/hp_82341/hp_82341.c @@ -79,10 +79,7 @@ static int hp_82341_accel_read(struct gpib_board *board, u8 *buffer, size_t leng int j; int count; - if (num_fifo_bytes - i < hp_82341_fifo_size) - block_size = num_fifo_bytes - i; - else - block_size = hp_82341_fifo_size; + block_size = min(num_fifo_bytes - i, hp_82341_fifo_size); set_transfer_counter(hp_priv, block_size); outb(ENABLE_TI_BUFFER_BIT | DIRECTION_GPIB_TO_HOST_BIT, hp_priv->iobase[3] + BUFFER_CONTROL_REG); @@ -195,10 +192,7 @@ static int hp_82341_accel_write(struct gpib_board *board, u8 *buffer, size_t len for (i = 0; i < fifo_xfer_len;) { int block_size; - if (fifo_xfer_len - i < hp_82341_fifo_size) - block_size = fifo_xfer_len - i; - else - block_size = hp_82341_fifo_size; + block_size = min(fifo_xfer_len - i, hp_82341_fifo_size); set_transfer_counter(hp_priv, block_size); // load data into board's fifo for (j = 0; j < block_size;) { diff --git a/drivers/staging/gpib/include/gpibP.h b/drivers/staging/gpib/include/gpibP.h index 0af72934ce241..1b27f37e0ba07 100644 --- a/drivers/staging/gpib/include/gpibP.h +++ b/drivers/staging/gpib/include/gpibP.h @@ -11,6 +11,7 @@ #include "gpib_types.h" #include "gpib_proto.h" +#include "gpib_cmd.h" #include "gpib.h" #include "gpib_ioctl.h" diff --git a/drivers/staging/gpib/include/gpib_cmd.h b/drivers/staging/gpib/include/gpib_cmd.h new file mode 100644 index 0000000000000..9e96a3bfa22d0 --- /dev/null +++ b/drivers/staging/gpib/include/gpib_cmd.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _GPIB_CMD_H +#define _GPIB_CMD_H + +#include <linux/types.h> + +/* Command byte definitions tests and functions */ + +/* mask of bits that actually matter in a command byte */ +enum { + gpib_command_mask = 0x7f, +}; + +/* Possible GPIB command messages */ + +enum cmd_byte { + GTL = 0x1, /* go to local */ + SDC = 0x4, /* selected device clear */ + PP_CONFIG = 0x5, + GET = 0x8, /* group execute trigger */ + TCT = 0x9, /* take control */ + LLO = 0x11, /* local lockout */ + DCL = 0x14, /* device clear */ + PPU = 0x15, /* parallel poll unconfigure */ + SPE = 0x18, /* serial poll enable */ + SPD = 0x19, /* serial poll disable */ + CFE = 0x1f, /* configure enable */ + LAD = 0x20, /* value to be 'ored' in to obtain listen address */ + UNL = 0x3F, /* unlisten */ + TAD = 0x40, /* value to be 'ored' in to obtain talk address */ + UNT = 0x5F, /* untalk */ + SAD = 0x60, /* my secondary address (base) */ + PPE = 0x60, /* parallel poll enable (base) */ + PPD = 0x70 /* parallel poll disable */ +}; + +/* confine address to range 0 to 30. */ +static inline unsigned int gpib_address_restrict(u32 addr) +{ + addr &= 0x1f; + if (addr == 0x1f) + addr = 0; + return addr; +} + +static inline u8 MLA(u32 addr) +{ + return gpib_address_restrict(addr) | LAD; +} + +static inline u8 MTA(u32 addr) +{ + return gpib_address_restrict(addr) | TAD; +} + +static inline u8 MSA(u32 addr) +{ + return (addr & 0x1f) | SAD; +} + +static inline s32 gpib_address_equal(u32 pad1, s32 sad1, u32 pad2, s32 sad2) +{ + if (pad1 == pad2) { + if (sad1 == sad2) + return 1; + if (sad1 < 0 && sad2 < 0) + return 1; + } + + return 0; +} + +static inline s32 is_PPE(u8 command) +{ + return (command & 0x70) == 0x60; +} + +static inline s32 is_PPD(u8 command) +{ + return (command & 0x70) == 0x70; +} + +static inline s32 in_addressed_command_group(u8 command) +{ + return (command & 0x70) == 0x0; +} + +static inline s32 in_universal_command_group(u8 command) +{ + return (command & 0x70) == 0x10; +} + +static inline s32 in_listen_address_group(u8 command) +{ + return (command & 0x60) == 0x20; +} + +static inline s32 in_talk_address_group(u8 command) +{ + return (command & 0x60) == 0x40; +} + +static inline s32 in_primary_command_group(u8 command) +{ + return in_addressed_command_group(command) || + in_universal_command_group(command) || + in_listen_address_group(command) || + in_talk_address_group(command); +} + +#endif /* _GPIB_CMD_H */ diff --git a/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c b/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c index 3cf5037c0cd2c..dd68c4843490a 100644 --- a/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c +++ b/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c @@ -791,7 +791,6 @@ static int usb_gpib_read(struct gpib_board *board, return -EIO; else return -ETIME; - return 0; } /* allocate buffer for multibyte read */ diff --git a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c index 7cf25c95787f3..73ea72f34c0a3 100644 --- a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c +++ b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c @@ -2079,10 +2079,10 @@ static int ni_usb_hs_wait_for_ready(struct ni_usb_priv *ni_priv) } if (buffer[++j] != 0x0) { // [6] ready = 1; - // NI-USB-HS+ sends 0xf here + // NI-USB-HS+ sends 0xf or 0x19 here if (buffer[j] != 0x2 && buffer[j] != 0xe && buffer[j] != 0xf && - buffer[j] != 0x16) { - dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x2, 0xe, 0xf or 0x16\n", + buffer[j] != 0x16 && buffer[j] != 0x19) { + dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x2, 0xe, 0xf, 0x16 or 0x19\n", j, (int)buffer[j]); unexpected = 1; } @@ -2110,11 +2110,11 @@ static int ni_usb_hs_wait_for_ready(struct ni_usb_priv *ni_priv) j, (int)buffer[j]); unexpected = 1; } - if (buffer[++j] != 0x0) { + if (buffer[++j] != 0x0) { // [10] MC usb-488 sends 0x7 here, new HS+ sends 0x59 ready = 1; - if (buffer[j] != 0x96 && buffer[j] != 0x7 && buffer[j] != 0x6e) { -// [10] MC usb-488 sends 0x7 here - dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x96, 0x07 or 0x6e\n", + if (buffer[j] != 0x96 && buffer[j] != 0x7 && buffer[j] != 0x6e && + buffer[j] != 0x59) { + dev_err(&usb_dev->dev, "unexpected data: buffer[%i]=0x%x, expected 0x96, 0x07, 0x6e or 0x59\n", j, (int)buffer[j]); unexpected = 1; } diff --git a/drivers/staging/gpib/uapi/gpib.h b/drivers/staging/gpib/uapi/gpib.h index 41500cee4029f..ddf82a4d989f3 100644 --- a/drivers/staging/gpib/uapi/gpib.h +++ b/drivers/staging/gpib/uapi/gpib.h @@ -83,204 +83,12 @@ enum bus_control_line { BUS_EOI = 0x8000 /* EOI line status bit */ }; -/* Possible GPIB command messages */ - -enum cmd_byte { - GTL = 0x1, /* go to local */ - SDC = 0x4, /* selected device clear */ - PP_CONFIG = 0x5, -#ifndef PPC - PPC = PP_CONFIG, /* parallel poll configure */ -#endif - GET = 0x8, /* group execute trigger */ - TCT = 0x9, /* take control */ - LLO = 0x11, /* local lockout */ - DCL = 0x14, /* device clear */ - PPU = 0x15, /* parallel poll unconfigure */ - SPE = 0x18, /* serial poll enable */ - SPD = 0x19, /* serial poll disable */ - CFE = 0x1f, /* configure enable */ - LAD = 0x20, /* value to be 'ored' in to obtain listen address */ - UNL = 0x3F, /* unlisten */ - TAD = 0x40, /* value to be 'ored' in to obtain talk address */ - UNT = 0x5F, /* untalk */ - SAD = 0x60, /* my secondary address (base) */ - PPE = 0x60, /* parallel poll enable (base) */ - PPD = 0x70 /* parallel poll disable */ -}; - enum ppe_bits { PPC_DISABLE = 0x10, PPC_SENSE = 0x8, /* parallel poll sense bit */ PPC_DIO_MASK = 0x7 }; -/* confine address to range 0 to 30. */ -static inline unsigned int gpib_address_restrict(unsigned int addr) -{ - addr &= 0x1f; - if (addr == 0x1f) - addr = 0; - return addr; -} - -static inline __u8 MLA(unsigned int addr) -{ - return gpib_address_restrict(addr) | LAD; -} - -static inline __u8 MTA(unsigned int addr) -{ - return gpib_address_restrict(addr) | TAD; -} - -static inline __u8 MSA(unsigned int addr) -{ - return (addr & 0x1f) | SAD; -} - -static inline __u8 PPE_byte(unsigned int dio_line, int sense) -{ - __u8 cmd; - - cmd = PPE; - if (sense) - cmd |= PPC_SENSE; - cmd |= (dio_line - 1) & 0x7; - return cmd; -} - -/* mask of bits that actually matter in a command byte */ -enum { - gpib_command_mask = 0x7f, -}; - -static inline int is_PPE(__u8 command) -{ - return (command & 0x70) == 0x60; -} - -static inline int is_PPD(__u8 command) -{ - return (command & 0x70) == 0x70; -} - -static inline int in_addressed_command_group(__u8 command) -{ - return (command & 0x70) == 0x0; -} - -static inline int in_universal_command_group(__u8 command) -{ - return (command & 0x70) == 0x10; -} - -static inline int in_listen_address_group(__u8 command) -{ - return (command & 0x60) == 0x20; -} - -static inline int in_talk_address_group(__u8 command) -{ - return (command & 0x60) == 0x40; -} - -static inline int in_primary_command_group(__u8 command) -{ - return in_addressed_command_group(command) || - in_universal_command_group(command) || - in_listen_address_group(command) || - in_talk_address_group(command); -} - -static inline int gpib_address_equal(unsigned int pad1, int sad1, unsigned int pad2, int sad2) -{ - if (pad1 == pad2) { - if (sad1 == sad2) - return 1; - if (sad1 < 0 && sad2 < 0) - return 1; - } - - return 0; -} - -enum ibask_option { - IBA_PAD = 0x1, - IBA_SAD = 0x2, - IBA_TMO = 0x3, - IBA_EOT = 0x4, - IBA_PPC = 0x5, /* board only */ - IBA_READ_DR = 0x6, /* device only */ - IBA_AUTOPOLL = 0x7, /* board only */ - IBA_CICPROT = 0x8, /* board only */ - IBA_IRQ = 0x9, /* board only */ - IBA_SC = 0xa, /* board only */ - IBA_SRE = 0xb, /* board only */ - IBA_EOS_RD = 0xc, - IBA_EOS_WRT = 0xd, - IBA_EOS_CMP = 0xe, - IBA_EOS_CHAR = 0xf, - IBA_PP2 = 0x10, /* board only */ - IBA_TIMING = 0x11, /* board only */ - IBA_DMA = 0x12, /* board only */ - IBA_READ_ADJUST = 0x13, - IBA_WRITE_ADJUST = 0x14, - IBA_EVENT_QUEUE = 0x15, /* board only */ - IBA_SPOLL_BIT = 0x16, /* board only */ - IBA_SEND_LLO = 0x17, /* board only */ - IBA_SPOLL_TIME = 0x18, /* device only */ - IBA_PPOLL_TIME = 0x19, /* board only */ - IBA_END_BIT_IS_NORMAL = 0x1a, - IBA_UN_ADDR = 0x1b, /* device only */ - IBA_HS_CABLE_LENGTH = 0x1f, /* board only */ - IBA_IST = 0x20, /* board only */ - IBA_RSV = 0x21, /* board only */ - IBA_BNA = 0x200, /* device only */ - /* linux-gpib extensions */ - IBA_7_BIT_EOS = 0x1000 /* board only. Returns 1 if board supports 7 bit eos compares*/ -}; - -enum ibconfig_option { - IBC_PAD = 0x1, - IBC_SAD = 0x2, - IBC_TMO = 0x3, - IBC_EOT = 0x4, - IBC_PPC = 0x5, /* board only */ - IBC_READDR = 0x6, /* device only */ - IBC_AUTOPOLL = 0x7, /* board only */ - IBC_CICPROT = 0x8, /* board only */ - IBC_IRQ = 0x9, /* board only */ - IBC_SC = 0xa, /* board only */ - IBC_SRE = 0xb, /* board only */ - IBC_EOS_RD = 0xc, - IBC_EOS_WRT = 0xd, - IBC_EOS_CMP = 0xe, - IBC_EOS_CHAR = 0xf, - IBC_PP2 = 0x10, /* board only */ - IBC_TIMING = 0x11, /* board only */ - IBC_DMA = 0x12, /* board only */ - IBC_READ_ADJUST = 0x13, - IBC_WRITE_ADJUST = 0x14, - IBC_EVENT_QUEUE = 0x15, /* board only */ - IBC_SPOLL_BIT = 0x16, /* board only */ - IBC_SEND_LLO = 0x17, /* board only */ - IBC_SPOLL_TIME = 0x18, /* device only */ - IBC_PPOLL_TIME = 0x19, /* board only */ - IBC_END_BIT_IS_NORMAL = 0x1a, - IBC_UN_ADDR = 0x1b, /* device only */ - IBC_HS_CABLE_LENGTH = 0x1f, /* board only */ - IBC_IST = 0x20, /* board only */ - IBC_RSV = 0x21, /* board only */ - IBC_BNA = 0x200 /* device only */ -}; - -enum t1_delays { - T1_DELAY_2000ns = 1, - T1_DELAY_500ns = 2, - T1_DELAY_350ns = 3 -}; - enum { request_service_bit = 0x40, }; @@ -292,11 +100,5 @@ enum gpib_events { EVENT_IFC = 3 }; -enum gpib_stb { - IB_STB_RQS = 0x40, /* IEEE 488.1 & 2 */ - IB_STB_ESB = 0x20, /* IEEE 488.2 only */ - IB_STB_MAV = 0x10 /* IEEE 488.2 only */ -}; - #endif /* _GPIB_H */ diff --git a/drivers/staging/gpib/uapi/gpib_ioctl.h b/drivers/staging/gpib/uapi/gpib_ioctl.h index 0fed5c0fa7f2a..55bf5e55507af 100644 --- a/drivers/staging/gpib/uapi/gpib_ioctl.h +++ b/drivers/staging/gpib/uapi/gpib_ioctl.h @@ -19,87 +19,90 @@ struct gpib_board_type_ioctl { /* argument for read/write/command ioctls */ struct gpib_read_write_ioctl { __u64 buffer_ptr; - unsigned int requested_transfer_count; - unsigned int completed_transfer_count; - int end; /* end flag return for reads, end io suppression request for cmd*/ - int handle; + __u32 requested_transfer_count; + __u32 completed_transfer_count; + __s32 end; /* end flag return for reads, end io suppression request for cmd*/ + __s32 handle; }; struct gpib_open_dev_ioctl { - unsigned int handle; - unsigned int pad; - int sad; - unsigned is_board : 1; + __u32 handle; + __u32 pad; + __s32 sad; + __u32 is_board; }; struct gpib_close_dev_ioctl { - unsigned int handle; + __u32 handle; }; struct gpib_serial_poll_ioctl { - unsigned int pad; - int sad; + __u32 pad; + __s32 sad; __u8 status_byte; + __u8 padding[3]; // align to 32 bit boundary }; struct gpib_eos_ioctl { - int eos; - int eos_flags; + __s32 eos; + __s32 eos_flags; }; struct gpib_wait_ioctl { - int handle; - int wait_mask; - int clear_mask; - int set_mask; - int ibsta; - int pad; - int sad; - unsigned int usec_timeout; + __s32 handle; + __s32 wait_mask; + __s32 clear_mask; + __s32 set_mask; + __s32 ibsta; + __s32 pad; + __s32 sad; + __u32 usec_timeout; }; struct gpib_online_ioctl { __u64 init_data_ptr; - int init_data_length; - int online; + __s32 init_data_length; + __s32 online; }; struct gpib_spoll_bytes_ioctl { - unsigned int num_bytes; - unsigned int pad; - int sad; + __u32 num_bytes; + __u32 pad; + __s32 sad; }; struct gpib_board_info_ioctl { - unsigned int pad; - int sad; - int parallel_poll_configuration; - int autopolling; - int is_system_controller; - unsigned int t1_delay; + __u32 pad; + __s32 sad; + __s32 parallel_poll_configuration; + __s32 autopolling; + __s32 is_system_controller; + __u32 t1_delay; unsigned ist : 1; unsigned no_7_bit_eos : 1; + unsigned padding :30; // align to 32 bit boundary }; struct gpib_select_pci_ioctl { - int pci_bus; - int pci_slot; + __s32 pci_bus; + __s32 pci_slot; }; struct gpib_ppoll_config_ioctl { __u8 config; unsigned set_ist : 1; unsigned clear_ist : 1; + unsigned padding :22; // align to 32 bit boundary }; struct gpib_pad_ioctl { - unsigned int handle; - unsigned int pad; + __u32 handle; + __u32 pad; }; struct gpib_sad_ioctl { - unsigned int handle; - int sad; + __u32 handle; + __s32 sad; }; // select a piece of hardware to attach by its sysfs device path @@ -110,7 +113,8 @@ struct gpib_select_device_path_ioctl { // update status byte and request service struct gpib_request_service2 { __u8 status_byte; - int new_reason_for_service; + __u8 padding[3]; // align to 32 bit boundary + __s32 new_reason_for_service; }; /* Standard functions. */ @@ -123,38 +127,38 @@ enum gpib_ioctl { IBWAIT = _IOWR(GPIB_CODE, 5, struct gpib_wait_ioctl), IBRPP = _IOWR(GPIB_CODE, 6, __u8), - IBSIC = _IOW(GPIB_CODE, 9, unsigned int), - IBSRE = _IOW(GPIB_CODE, 10, int), + IBSIC = _IOW(GPIB_CODE, 9, __u32), + IBSRE = _IOW(GPIB_CODE, 10, __s32), IBGTS = _IO(GPIB_CODE, 11), - IBCAC = _IOW(GPIB_CODE, 12, int), - IBLINES = _IOR(GPIB_CODE, 14, short), + IBCAC = _IOW(GPIB_CODE, 12, __s32), + IBLINES = _IOR(GPIB_CODE, 14, __s16), IBPAD = _IOW(GPIB_CODE, 15, struct gpib_pad_ioctl), IBSAD = _IOW(GPIB_CODE, 16, struct gpib_sad_ioctl), - IBTMO = _IOW(GPIB_CODE, 17, unsigned int), + IBTMO = _IOW(GPIB_CODE, 17, __u32), IBRSP = _IOWR(GPIB_CODE, 18, struct gpib_serial_poll_ioctl), IBEOS = _IOW(GPIB_CODE, 19, struct gpib_eos_ioctl), IBRSV = _IOW(GPIB_CODE, 20, __u8), CFCBASE = _IOW(GPIB_CODE, 21, __u64), - CFCIRQ = _IOW(GPIB_CODE, 22, unsigned int), - CFCDMA = _IOW(GPIB_CODE, 23, unsigned int), + CFCIRQ = _IOW(GPIB_CODE, 22, __u32), + CFCDMA = _IOW(GPIB_CODE, 23, __u32), CFCBOARDTYPE = _IOW(GPIB_CODE, 24, struct gpib_board_type_ioctl), - IBMUTEX = _IOW(GPIB_CODE, 26, int), + IBMUTEX = _IOW(GPIB_CODE, 26, __s32), IBSPOLL_BYTES = _IOWR(GPIB_CODE, 27, struct gpib_spoll_bytes_ioctl), IBPPC = _IOW(GPIB_CODE, 28, struct gpib_ppoll_config_ioctl), IBBOARD_INFO = _IOR(GPIB_CODE, 29, struct gpib_board_info_ioctl), - IBQUERY_BOARD_RSV = _IOR(GPIB_CODE, 31, int), + IBQUERY_BOARD_RSV = _IOR(GPIB_CODE, 31, __s32), IBSELECT_PCI = _IOWR(GPIB_CODE, 32, struct gpib_select_pci_ioctl), - IBEVENT = _IOR(GPIB_CODE, 33, short), - IBRSC = _IOW(GPIB_CODE, 34, int), - IB_T1_DELAY = _IOW(GPIB_CODE, 35, unsigned int), + IBEVENT = _IOR(GPIB_CODE, 33, __s16), + IBRSC = _IOW(GPIB_CODE, 34, __s32), + IB_T1_DELAY = _IOW(GPIB_CODE, 35, __u32), IBLOC = _IO(GPIB_CODE, 36), - IBAUTOSPOLL = _IOW(GPIB_CODE, 38, short), + IBAUTOSPOLL = _IOW(GPIB_CODE, 38, __s16), IBONL = _IOW(GPIB_CODE, 39, struct gpib_online_ioctl), - IBPP2_SET = _IOW(GPIB_CODE, 40, short), - IBPP2_GET = _IOR(GPIB_CODE, 41, short), + IBPP2_SET = _IOW(GPIB_CODE, 40, __s16), + IBPP2_GET = _IOR(GPIB_CODE, 41, __s16), IBSELECT_DEVICE_PATH = _IOW(GPIB_CODE, 43, struct gpib_select_device_path_ioctl), // 44 was IBSELECT_SERIAL_NUMBER IBRSV2 = _IOW(GPIB_CODE, 45, struct gpib_request_service2) diff --git a/drivers/staging/greybus/Documentation/firmware/firmware.c b/drivers/staging/greybus/Documentation/firmware/firmware.c index 765d69faa9cc9..3b35ef6d4adbb 100644 --- a/drivers/staging/greybus/Documentation/firmware/firmware.c +++ b/drivers/staging/greybus/Documentation/firmware/firmware.c @@ -47,12 +47,12 @@ static int update_intf_firmware(int fd) ret = ioctl(fd, FW_MGMT_IOC_GET_INTF_FW, &intf_fw_info); if (ret < 0) { printf("Failed to get interface firmware version: %s (%d)\n", - fwdev, ret); + fwdev, ret); return -1; } printf("Interface Firmware tag (%s), major (%d), minor (%d)\n", - intf_fw_info.firmware_tag, intf_fw_info.major, + intf_fw_info.firmware_tag, intf_fw_info.major, intf_fw_info.minor); /* Try Interface Firmware load over Unipro */ @@ -69,20 +69,20 @@ static int update_intf_firmware(int fd) ret = ioctl(fd, FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE, &intf_load); if (ret < 0) { printf("Failed to load interface firmware: %s (%d)\n", fwdev, - ret); + ret); return -1; } if (intf_load.status != GB_FW_U_LOAD_STATUS_VALIDATED && intf_load.status != GB_FW_U_LOAD_STATUS_UNVALIDATED) { printf("Load status says loading failed: %d\n", - intf_load.status); + intf_load.status); return -1; } printf("Interface Firmware (%s) Load done: major: %d, minor: %d, status: %d\n", - firmware_tag, intf_load.major, intf_load.minor, - intf_load.status); + firmware_tag, intf_load.major, intf_load.minor, + intf_load.status); /* Initiate Mode-switch to the newly loaded firmware */ printf("Initiate Mode switch\n"); @@ -108,21 +108,21 @@ retry_fw_version: ret = ioctl(fd, FW_MGMT_IOC_GET_BACKEND_FW, &backend_fw_info); if (ret < 0) { printf("Failed to get backend firmware version: %s (%d)\n", - fwdev, ret); + fwdev, ret); return -1; } printf("Backend Firmware tag (%s), major (%d), minor (%d), status (%d)\n", - backend_fw_info.firmware_tag, backend_fw_info.major, + backend_fw_info.firmware_tag, backend_fw_info.major, backend_fw_info.minor, backend_fw_info.status); if (backend_fw_info.status == GB_FW_U_BACKEND_VERSION_STATUS_RETRY) goto retry_fw_version; - if ((backend_fw_info.status != GB_FW_U_BACKEND_VERSION_STATUS_SUCCESS) - && (backend_fw_info.status != GB_FW_U_BACKEND_VERSION_STATUS_NOT_AVAILABLE)) { + if ((backend_fw_info.status != GB_FW_U_BACKEND_VERSION_STATUS_SUCCESS) && + (backend_fw_info.status != GB_FW_U_BACKEND_VERSION_STATUS_NOT_AVAILABLE)) { printf("Failed to get backend firmware version: %s (%d)\n", - fwdev, backend_fw_info.status); + fwdev, backend_fw_info.status); return -1; } @@ -148,10 +148,10 @@ retry_fw_update: if (backend_update.status != GB_FW_U_BACKEND_FW_STATUS_SUCCESS) { printf("Load status says loading failed: %d\n", - backend_update.status); + backend_update.status); } else { printf("Backend Firmware (%s) Load done: status: %d\n", - firmware_tag, backend_update.status); + firmware_tag, backend_update.status); } return 0; @@ -185,7 +185,7 @@ int main(int argc, char *argv[]) fw_timeout = strtoul(argv[4], &endptr, 10); printf("Trying Firmware update: fwdev: %s, type: %s, tag: %s, timeout: %u\n", - fwdev, fw_update_type == 0 ? "interface" : "backend", + fwdev, fw_update_type == 0 ? "interface" : "backend", firmware_tag, fw_timeout); printf("Opening %s firmware management device\n", fwdev); diff --git a/drivers/staging/greybus/camera.c b/drivers/staging/greybus/camera.c index ec9fddfc0b14d..5ac19c0055d95 100644 --- a/drivers/staging/greybus/camera.c +++ b/drivers/staging/greybus/camera.c @@ -1128,7 +1128,7 @@ done: static int gb_camera_debugfs_open(struct inode *inode, struct file *file) { - file->private_data = (void *)debugfs_get_aux(file); + file->private_data = debugfs_get_aux(file); return 0; } diff --git a/drivers/staging/greybus/gbphy.c b/drivers/staging/greybus/gbphy.c index 6adcad2866330..60cf09a302a7e 100644 --- a/drivers/staging/greybus/gbphy.c +++ b/drivers/staging/greybus/gbphy.c @@ -102,8 +102,8 @@ static int gbphy_dev_uevent(const struct device *dev, struct kobj_uevent_env *en } static const struct gbphy_device_id * -gbphy_dev_match_id(struct gbphy_device *gbphy_dev, - struct gbphy_driver *gbphy_drv) +gbphy_dev_match_id(const struct gbphy_device *gbphy_dev, + const struct gbphy_driver *gbphy_drv) { const struct gbphy_device_id *id = gbphy_drv->id_table; @@ -119,7 +119,7 @@ gbphy_dev_match_id(struct gbphy_device *gbphy_dev, static int gbphy_dev_match(struct device *dev, const struct device_driver *drv) { - struct gbphy_driver *gbphy_drv = to_gbphy_driver(drv); + const struct gbphy_driver *gbphy_drv = to_gbphy_driver(drv); struct gbphy_device *gbphy_dev = to_gbphy_dev(dev); const struct gbphy_device_id *id; diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c index f81c34160f720..1280530c8987a 100644 --- a/drivers/staging/greybus/gpio.c +++ b/drivers/staging/greybus/gpio.c @@ -192,12 +192,6 @@ static int gb_gpio_set_value_operation(struct gb_gpio_controller *ggc, struct gb_gpio_set_value_request request; int ret; - if (ggc->lines[which].direction == 1) { - dev_warn(dev, "refusing to set value of input gpio %u\n", - which); - return -EPERM; - } - request.which = which; request.value = value_high ? 1 : 0; ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_SET_VALUE, diff --git a/drivers/staging/greybus/power_supply.c b/drivers/staging/greybus/power_supply.c index 2ef46822f676d..a484c0ca058d8 100644 --- a/drivers/staging/greybus/power_supply.c +++ b/drivers/staging/greybus/power_supply.c @@ -324,7 +324,7 @@ static struct gb_power_supply_prop *get_psy_prop(struct gb_power_supply *gbpsy, } static int is_psy_prop_writeable(struct gb_power_supply *gbpsy, - enum power_supply_property psp) + enum power_supply_property psp) { struct gb_power_supply_prop *prop; @@ -493,7 +493,7 @@ static int gb_power_supply_description_get(struct gb_power_supply *gbpsy) if (!gbpsy->model_name) return -ENOMEM; gbpsy->serial_number = kstrndup(resp.serial_number, PROP_MAX, - GFP_KERNEL); + GFP_KERNEL); if (!gbpsy->serial_number) return -ENOMEM; @@ -546,7 +546,7 @@ static int gb_power_supply_prop_descriptors_get(struct gb_power_supply *gbpsy) } gbpsy->props = kcalloc(gbpsy->properties_count, sizeof(*gbpsy->props), - GFP_KERNEL); + GFP_KERNEL); if (!gbpsy->props) { ret = -ENOMEM; goto out_put_operation; @@ -634,8 +634,8 @@ static int __gb_power_supply_property_get(struct gb_power_supply *gbpsy, } static int __gb_power_supply_property_strval_get(struct gb_power_supply *gbpsy, - enum power_supply_property psp, - union power_supply_propval *val) + enum power_supply_property psp, + union power_supply_propval *val) { switch (psp) { case POWER_SUPPLY_PROP_MODEL_NAME: @@ -943,8 +943,8 @@ static int gb_power_supplies_setup(struct gb_power_supplies *supplies) goto out; supplies->supply = kcalloc(supplies->supplies_count, - sizeof(struct gb_power_supply), - GFP_KERNEL); + sizeof(struct gb_power_supply), + GFP_KERNEL); if (!supplies->supply) { ret = -ENOMEM; diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c index 308ed1ca99472..10df5c37c83ed 100644 --- a/drivers/staging/greybus/uart.c +++ b/drivers/staging/greybus/uart.c @@ -916,7 +916,6 @@ static void gb_uart_remove(struct gbphy_device *gbphy_dev) { struct gb_tty *gb_tty = gb_gbphy_get_data(gbphy_dev); struct gb_connection *connection = gb_tty->connection; - struct tty_struct *tty; int ret; ret = gbphy_runtime_get_sync(gbphy_dev); @@ -929,11 +928,7 @@ static void gb_uart_remove(struct gbphy_device *gbphy_dev) wake_up_all(&gb_tty->wioctl); mutex_unlock(&gb_tty->mutex); - tty = tty_port_tty_get(&gb_tty->port); - if (tty) { - tty_vhangup(tty); - tty_kref_put(tty); - } + tty_port_tty_vhangup(&gb_tty->port); gb_connection_disable_rx(connection); tty_unregister_device(gb_tty_driver, gb_tty->minor); diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index b442148543995..ab250c89cd4d4 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -28,12 +28,12 @@ source "drivers/staging/media/imx/Kconfig" source "drivers/staging/media/ipu3/Kconfig" +source "drivers/staging/media/ipu7/Kconfig" + source "drivers/staging/media/max96712/Kconfig" source "drivers/staging/media/meson/vdec/Kconfig" -source "drivers/staging/media/rkvdec/Kconfig" - source "drivers/staging/media/starfive/Kconfig" source "drivers/staging/media/sunxi/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index ad4e9619a9e07..4a073938b2b2d 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -4,9 +4,9 @@ obj-$(CONFIG_INTEL_ATOMISP) += atomisp/ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ obj-$(CONFIG_VIDEO_MAX96712) += max96712/ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ -obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/ obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ +obj-$(CONFIG_VIDEO_INTEL_IPU7) += ipu7/ obj-$(CONFIG_DVB_AV7110) += av7110/ diff --git a/drivers/staging/media/atomisp/Kconfig b/drivers/staging/media/atomisp/Kconfig index 1265fc58a2328..fbe507ae6ec6e 100644 --- a/drivers/staging/media/atomisp/Kconfig +++ b/drivers/staging/media/atomisp/Kconfig @@ -12,6 +12,7 @@ menuconfig INTEL_ATOMISP config VIDEO_ATOMISP tristate "Intel Atom Image Signal Processor Driver" depends on VIDEO_DEV && INTEL_ATOMISP + depends on INTEL_SKL_INT3472 depends on IPU_BRIDGE depends on MEDIA_PCI_SUPPORT depends on PMIC_OPREGION diff --git a/drivers/staging/media/atomisp/Makefile b/drivers/staging/media/atomisp/Makefile index 43116c74781d0..1d0fbe22036bd 100644 --- a/drivers/staging/media/atomisp/Makefile +++ b/drivers/staging/media/atomisp/Makefile @@ -17,7 +17,6 @@ atomisp-objs += \ pci/atomisp_compat_css20.o \ pci/atomisp_csi2.o \ pci/atomisp_csi2_bridge.o \ - pci/atomisp_drvfs.o \ pci/atomisp_fops.o \ pci/atomisp_ioctl.o \ pci/atomisp_subdev.o \ diff --git a/drivers/staging/media/atomisp/TODO b/drivers/staging/media/atomisp/TODO index 27cbbde93b1ee..82be275b4a0aa 100644 --- a/drivers/staging/media/atomisp/TODO +++ b/drivers/staging/media/atomisp/TODO @@ -7,8 +7,6 @@ TODO * Remove/disable custom v4l2-ctrls -* Remove custom sysfs files created by atomisp_drvfs.c - * Remove unnecessary/unwanted module parameters * Remove abuse of priv field in various v4l2 userspace API structs diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index 4f46182da58b2..ef2094c223472 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -31,6 +31,7 @@ config VIDEO_ATOMISP_GC0310 tristate "GC0310 sensor support" depends on ACPI depends on I2C && VIDEO_DEV + select V4L2_CCI_I2C help This is a Video4Linux2 sensor-level driver for the Galaxycore GC0310 0.3MP sensor. diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index d35394f1ddbb8..7af4d66f42a0f 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -3,7 +3,7 @@ * Support for GalaxyCore GC0310 VGA camera sensor. * * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * Copyright (c) 2023 Hans de Goede <hdegoede@redhat.com> + * Copyright (c) 2023-2025 Hans de Goede <hansg@kernel.org> */ #include <linux/delay.h> @@ -13,77 +13,92 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/regmap.h> #include <linux/string.h> #include <linux/types.h> +#include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> #define GC0310_NATIVE_WIDTH 656 #define GC0310_NATIVE_HEIGHT 496 +/* + * The actual PLL output rate is unknown, the datasheet + * says that the formula for the frame-time in pixels is: + * rowtime = win-width + hblank + sh-delay + 4 + * frametime = rowtime * (win-height + vblank) + * Filling this in and multiplying by 30 fps gives: + * pixelrate = (660 + 178 + 42 + 4) * (498 + 27) * 30 = 13923000 + */ +#define GC0310_PIXELRATE 13923000 +/* single lane, bus-format is 8 bpp, CSI-2 is double data rate */ +#define GC0310_LINK_FREQ (GC0310_PIXELRATE * 8 / 2) +#define GC0310_MCLK_FREQ 19200000 #define GC0310_FPS 30 #define GC0310_SKIP_FRAMES 3 -#define GC0310_FOCAL_LENGTH_NUM 278 /* 2.78mm */ - #define GC0310_ID 0xa310 -#define GC0310_RESET_RELATED 0xFE +#define GC0310_RESET_RELATED_REG CCI_REG8(0xfe) #define GC0310_REGISTER_PAGE_0 0x0 #define GC0310_REGISTER_PAGE_3 0x3 /* * GC0310 System control registers */ -#define GC0310_SW_STREAM 0x10 - -#define GC0310_SC_CMMN_CHIP_ID_H 0xf0 -#define GC0310_SC_CMMN_CHIP_ID_L 0xf1 - -#define GC0310_AEC_PK_EXPO_H 0x03 -#define GC0310_AEC_PK_EXPO_L 0x04 -#define GC0310_AGC_ADJ 0x48 -#define GC0310_DGC_ADJ 0x71 -#define GC0310_GROUP_ACCESS 0x3208 - -#define GC0310_H_CROP_START_H 0x09 -#define GC0310_H_CROP_START_L 0x0A -#define GC0310_V_CROP_START_H 0x0B -#define GC0310_V_CROP_START_L 0x0C -#define GC0310_H_OUTSIZE_H 0x0F -#define GC0310_H_OUTSIZE_L 0x10 -#define GC0310_V_OUTSIZE_H 0x0D -#define GC0310_V_OUTSIZE_L 0x0E -#define GC0310_H_BLANKING_H 0x05 -#define GC0310_H_BLANKING_L 0x06 -#define GC0310_V_BLANKING_H 0x07 -#define GC0310_V_BLANKING_L 0x08 -#define GC0310_SH_DELAY 0x11 +#define GC0310_SW_STREAM_REG CCI_REG8(0x10) #define GC0310_START_STREAMING 0x94 /* 8-bit enable */ #define GC0310_STOP_STREAMING 0x0 /* 8-bit disable */ +#define GC0310_SC_CMMN_CHIP_ID_REG CCI_REG16(0xf0) + +#define GC0310_AEC_PK_EXPO_REG CCI_REG16(0x03) +#define GC0310_AGC_ADJ_REG CCI_REG8(0x48) +#define GC0310_DGC_ADJ_REG CCI_REG8(0x71) + +#define GC0310_H_CROP_START_REG CCI_REG16(0x09) +#define GC0310_V_CROP_START_REG CCI_REG16(0x0b) +#define GC0310_H_OUTSIZE_REG CCI_REG16(0x0f) +#define GC0310_V_OUTSIZE_REG CCI_REG16(0x0d) + +#define GC0310_H_BLANKING_REG CCI_REG16(0x05) +/* Hblank-register + sh-delay + H-crop + 4 (from hw) */ +#define GC0310_H_BLANK_DEFAULT (178 + 42 + 4 + 4) + +#define GC0310_V_BLANKING_REG CCI_REG16(0x07) +/* Vblank needs an offset compensate for the small V-crop done */ +#define GC0310_V_BLANK_OFFSET 2 +/* Vsync start time + 1 row vsync + vsync end time + offset */ +#define GC0310_V_BLANK_MIN (9 + 1 + 4 + GC0310_V_BLANK_OFFSET) +#define GC0310_V_BLANK_DEFAULT (27 + GC0310_V_BLANK_OFFSET) +#define GC0310_V_BLANK_MAX (4095 - GC0310_NATIVE_HEIGHT) + +#define GC0310_SH_DELAY_REG CCI_REG8(0x11) +#define GC0310_VS_START_TIME_REG CCI_REG8(0x12) +#define GC0310_VS_END_TIME_REG CCI_REG8(0x13) + #define to_gc0310_sensor(x) container_of(x, struct gc0310_device, sd) struct gc0310_device { struct v4l2_subdev sd; struct media_pad pad; - /* Protect against concurrent changes to controls */ - struct mutex input_lock; - bool is_streaming; + struct regmap *regmap; struct gpio_desc *reset; struct gpio_desc *powerdown; - struct gc0310_mode { - struct v4l2_mbus_framefmt fmt; - } mode; - struct gc0310_ctrls { struct v4l2_ctrl_handler handler; struct v4l2_ctrl *exposure; struct v4l2_ctrl *gain; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; } ctrls; }; @@ -92,7 +107,7 @@ struct gc0310_reg { u8 val; }; -static const struct gc0310_reg gc0310_reset_register[] = { +static const struct reg_sequence gc0310_reset_register[] = { /* System registers */ { 0xfe, 0xf0 }, { 0xfe, 0xf0 }, @@ -142,8 +157,7 @@ static const struct gc0310_reg gc0310_reset_register[] = { { 0x04, 0xc0 }, /* 0xe8 //58 */ { 0x05, 0x00 }, { 0x06, 0xb2 }, /* 0x0a //HB */ - { 0x07, 0x00 }, - { 0x08, 0x0c }, /* 0x89 //VB */ + /* Vblank (reg 0x07 + 0x08) gets set by the vblank ctrl */ { 0x09, 0x00 }, /* row start */ { 0x0a, 0x00 }, { 0x0b, 0x00 }, /* col start */ @@ -235,7 +249,7 @@ static const struct gc0310_reg gc0310_reset_register[] = { { 0xfe, 0x00 }, }; -static const struct gc0310_reg gc0310_VGA_30fps[] = { +static const struct reg_sequence gc0310_VGA_30fps[] = { { 0xfe, 0x00 }, { 0x0d, 0x01 }, /* height */ { 0x0e, 0xf2 }, /* 0xf7 //height */ @@ -259,41 +273,14 @@ static const struct gc0310_reg gc0310_VGA_30fps[] = { { 0xfe, 0x00 }, }; -/* - * gc0310_write_reg_array - Initializes a list of GC0310 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * @count: number of register, value pairs in the list - */ -static int gc0310_write_reg_array(struct i2c_client *client, - const struct gc0310_reg *reglist, int count) -{ - int i, err; - - for (i = 0; i < count; i++) { - err = i2c_smbus_write_byte_data(client, reglist[i].reg, reglist[i].val); - if (err) { - dev_err(&client->dev, "write error: wrote 0x%x to offset 0x%x error %d", - reglist[i].val, reglist[i].reg, err); - return err; - } - } - - return 0; -} - -static int gc0310_exposure_set(struct gc0310_device *dev, u32 exp) -{ - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - - return i2c_smbus_write_word_swapped(client, GC0310_AEC_PK_EXPO_H, exp); -} +static const s64 link_freq_menu_items[] = { + GC0310_LINK_FREQ, +}; -static int gc0310_gain_set(struct gc0310_device *dev, u32 gain) +static int gc0310_gain_set(struct gc0310_device *sensor, u32 gain) { - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); u8 again, dgain; - int ret; + int ret = 0; /* Taken from original driver, this never sets dgain lower then 32? */ @@ -308,36 +295,55 @@ static int gc0310_gain_set(struct gc0310_device *dev, u32 gain) dgain = gain / 2; } - ret = i2c_smbus_write_byte_data(client, GC0310_AGC_ADJ, again); - if (ret) - return ret; + cci_write(sensor->regmap, GC0310_AGC_ADJ_REG, again, &ret); + cci_write(sensor->regmap, GC0310_DGC_ADJ_REG, dgain, &ret); + return ret; +} + +static int gc0310_exposure_update_range(struct gc0310_device *sensor) +{ + int exp_max = GC0310_NATIVE_HEIGHT + sensor->ctrls.vblank->val; - return i2c_smbus_write_byte_data(client, GC0310_DGC_ADJ, dgain); + return __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 0, exp_max, + 1, exp_max); } static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl) { - struct gc0310_device *dev = + struct gc0310_device *sensor = container_of(ctrl->handler, struct gc0310_device, ctrls.handler); int ret; + /* Update exposure range on vblank changes */ + if (ctrl->id == V4L2_CID_VBLANK) { + ret = gc0310_exposure_update_range(sensor); + if (ret) + return ret; + } + /* Only apply changes to the controls if the device is powered up */ - if (!pm_runtime_get_if_in_use(dev->sd.dev)) + if (!pm_runtime_get_if_in_use(sensor->sd.dev)) return 0; switch (ctrl->id) { case V4L2_CID_EXPOSURE: - ret = gc0310_exposure_set(dev, ctrl->val); + ret = cci_write(sensor->regmap, GC0310_AEC_PK_EXPO_REG, + ctrl->val, NULL); break; - case V4L2_CID_GAIN: - ret = gc0310_gain_set(dev, ctrl->val); + case V4L2_CID_ANALOGUE_GAIN: + ret = gc0310_gain_set(sensor, ctrl->val); + break; + case V4L2_CID_VBLANK: + ret = cci_write(sensor->regmap, GC0310_V_BLANKING_REG, + ctrl->val - GC0310_V_BLANK_OFFSET, + NULL); break; default: ret = -EINVAL; break; } - pm_runtime_put(dev->sd.dev); + pm_runtime_put(sensor->sd.dev); return ret; } @@ -345,17 +351,6 @@ static const struct v4l2_ctrl_ops ctrl_ops = { .s_ctrl = gc0310_s_ctrl, }; -static struct v4l2_mbus_framefmt * -gc0310_get_pad_format(struct gc0310_device *dev, - struct v4l2_subdev_state *state, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_state_get_format(state, pad); - - return &dev->mode.fmt; -} - /* The GC0310 currently only supports 1 fixed fmt */ static void gc0310_fill_format(struct v4l2_mbus_framefmt *fmt) { @@ -366,54 +361,72 @@ static void gc0310_fill_format(struct v4l2_mbus_framefmt *fmt) fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; } -static int gc0310_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) +static int gc0310_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) { - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct v4l2_mbus_framefmt *fmt; + /* Only the single fixed 656x496 mode is supported, without croping */ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = GC0310_NATIVE_WIDTH; + sel->r.height = GC0310_NATIVE_HEIGHT; + break; + default: + return -EINVAL; + } + + return 0; +} - fmt = gc0310_get_pad_format(dev, sd_state, format->pad, format->which); - gc0310_fill_format(fmt); +static int gc0310_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct gc0310_device *sensor = to_gc0310_sensor(sd); - format->format = *fmt; + gpiod_set_value_cansleep(sensor->powerdown, 1); + gpiod_set_value_cansleep(sensor->reset, 1); return 0; } -static int gc0310_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) +static int gc0310_power_on(struct device *dev) { - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct v4l2_mbus_framefmt *fmt; + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct gc0310_device *sensor = to_gc0310_sensor(sd); + + fsleep(10 * USEC_PER_MSEC); + gpiod_set_value_cansleep(sensor->reset, 0); + fsleep(10 * USEC_PER_MSEC); + gpiod_set_value_cansleep(sensor->powerdown, 0); + fsleep(10 * USEC_PER_MSEC); - fmt = gc0310_get_pad_format(dev, sd_state, format->pad, format->which); - format->format = *fmt; return 0; } -static int gc0310_detect(struct i2c_client *client) +static int gc0310_detect(struct gc0310_device *sensor) { - struct i2c_adapter *adapter = client->adapter; + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); + u64 val; int ret; - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; - ret = pm_runtime_get_sync(&client->dev); - if (ret >= 0) - ret = i2c_smbus_read_word_swapped(client, GC0310_SC_CMMN_CHIP_ID_H); - pm_runtime_put(&client->dev); + ret = cci_read(sensor->regmap, GC0310_SC_CMMN_CHIP_ID_REG, &val, NULL); if (ret < 0) { dev_err(&client->dev, "read sensor_id failed: %d\n", ret); return -ENODEV; } - dev_dbg(&client->dev, "sensor ID = 0x%x\n", ret); + dev_dbg(&client->dev, "sensor ID = 0x%llx\n", val); - if (ret != GC0310_ID) { - dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n", - ret, GC0310_ID); + if (val != GC0310_ID) { + dev_err(&client->dev, "sensor ID error, read id = 0x%llx, target id = 0x%x\n", + val, GC0310_ID); return -ENODEV; } @@ -422,85 +435,67 @@ static int gc0310_detect(struct i2c_client *client) return 0; } -static int gc0310_s_stream(struct v4l2_subdev *sd, int enable) +static int gc0310_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) { - struct gc0310_device *dev = to_gc0310_sensor(sd); + struct gc0310_device *sensor = to_gc0310_sensor(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - dev_dbg(&client->dev, "%s S enable=%d\n", __func__, enable); - mutex_lock(&dev->input_lock); - - if (enable) { - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) - goto error_power_down; - - msleep(100); - - ret = gc0310_write_reg_array(client, gc0310_reset_register, - ARRAY_SIZE(gc0310_reset_register)); - if (ret) - goto error_power_down; - - ret = gc0310_write_reg_array(client, gc0310_VGA_30fps, - ARRAY_SIZE(gc0310_VGA_30fps)); - if (ret) - goto error_power_down; - - /* restore value of all ctrls */ - ret = __v4l2_ctrl_handler_setup(&dev->ctrls.handler); - if (ret) - goto error_power_down; - - /* enable per frame MIPI and sensor ctrl reset */ - ret = i2c_smbus_write_byte_data(client, 0xFE, 0x30); - if (ret) - goto error_power_down; - } + int ret; - ret = i2c_smbus_write_byte_data(client, GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_3); + ret = pm_runtime_resume_and_get(&client->dev); if (ret) - goto error_power_down; + return ret; - ret = i2c_smbus_write_byte_data(client, GC0310_SW_STREAM, - enable ? GC0310_START_STREAMING : GC0310_STOP_STREAMING); + ret = regmap_multi_reg_write(sensor->regmap, + gc0310_reset_register, + ARRAY_SIZE(gc0310_reset_register)); if (ret) goto error_power_down; - ret = i2c_smbus_write_byte_data(client, GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_0); + ret = regmap_multi_reg_write(sensor->regmap, + gc0310_VGA_30fps, + ARRAY_SIZE(gc0310_VGA_30fps)); if (ret) goto error_power_down; - if (!enable) - pm_runtime_put(&client->dev); + /* restore value of all ctrls */ + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); - dev->is_streaming = enable; - mutex_unlock(&dev->input_lock); - return 0; + /* enable per frame MIPI and sensor ctrl reset */ + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, 0x30, &ret); + + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, + GC0310_REGISTER_PAGE_3, &ret); + cci_write(sensor->regmap, GC0310_SW_STREAM_REG, + GC0310_START_STREAMING, &ret); + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, + GC0310_REGISTER_PAGE_0, &ret); error_power_down: - pm_runtime_put(&client->dev); - dev->is_streaming = false; - mutex_unlock(&dev->input_lock); + if (ret) + pm_runtime_put(&client->dev); + return ret; } -static int gc0310_get_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_interval *interval) +static int gc0310_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) { - /* - * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 - * subdev active state API. - */ - if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; + struct gc0310_device *sensor = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; - interval->interval.numerator = 1; - interval->interval.denominator = GC0310_FPS; + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, + GC0310_REGISTER_PAGE_3, &ret); + cci_write(sensor->regmap, GC0310_SW_STREAM_REG, + GC0310_STOP_STREAMING, &ret); + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, + GC0310_REGISTER_PAGE_0, &ret); - return 0; + pm_runtime_put(&client->dev); + return ret; } static int gc0310_enum_mbus_code(struct v4l2_subdev *sd, @@ -531,164 +526,239 @@ static int gc0310_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int gc0310_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - *frames = GC0310_SKIP_FRAMES; - return 0; -} - -static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = { - .g_skip_frames = gc0310_g_skip_frames, -}; - static const struct v4l2_subdev_video_ops gc0310_video_ops = { - .s_stream = gc0310_s_stream, + .s_stream = v4l2_subdev_s_stream_helper, }; static const struct v4l2_subdev_pad_ops gc0310_pad_ops = { .enum_mbus_code = gc0310_enum_mbus_code, .enum_frame_size = gc0310_enum_frame_size, - .get_fmt = gc0310_get_fmt, - .set_fmt = gc0310_set_fmt, - .get_frame_interval = gc0310_get_frame_interval, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = v4l2_subdev_get_fmt, /* Only 1 fixed mode supported */ + .get_selection = gc0310_get_selection, + .set_selection = gc0310_get_selection, + .enable_streams = gc0310_enable_streams, + .disable_streams = gc0310_disable_streams, }; static const struct v4l2_subdev_ops gc0310_ops = { .video = &gc0310_video_ops, .pad = &gc0310_pad_ops, - .sensor = &gc0310_sensor_ops, }; -static int gc0310_init_controls(struct gc0310_device *dev) +static int gc0310_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { - struct v4l2_ctrl_handler *hdl = &dev->ctrls.handler; + gc0310_fill_format(v4l2_subdev_state_get_format(sd_state, 0)); + return 0; +} - v4l2_ctrl_handler_init(hdl, 2); +static const struct v4l2_subdev_internal_ops gc0310_internal_ops = { + .init_state = gc0310_init_state, +}; + +static int gc0310_init_controls(struct gc0310_device *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); + struct v4l2_ctrl_handler *hdl = &sensor->ctrls.handler; + struct v4l2_fwnode_device_properties props; + int exp_max, ret; + + v4l2_ctrl_handler_init(hdl, 8); /* Use the same lock for controls as for everything else */ - hdl->lock = &dev->input_lock; - dev->sd.ctrl_handler = hdl; + sensor->sd.ctrl_handler = hdl; - dev->ctrls.exposure = - v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_EXPOSURE, 0, 4095, 1, 1023); + exp_max = GC0310_NATIVE_HEIGHT + GC0310_V_BLANK_DEFAULT; + sensor->ctrls.exposure = + v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_EXPOSURE, 0, + exp_max, 1, exp_max); /* 32 steps at base gain 1 + 64 half steps at base gain 2 */ - dev->ctrls.gain = - v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_GAIN, 0, 95, 1, 31); + sensor->ctrls.gain = + v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_ANALOGUE_GAIN, 0, 95, 1, 31); + + sensor->ctrls.link_freq = + v4l2_ctrl_new_int_menu(hdl, NULL, V4L2_CID_LINK_FREQ, + 0, 0, link_freq_menu_items); + sensor->ctrls.pixel_rate = + v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_PIXEL_RATE, 0, + GC0310_PIXELRATE, 1, GC0310_PIXELRATE); + + sensor->ctrls.vblank = + v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_VBLANK, + GC0310_V_BLANK_MIN, + GC0310_V_BLANK_MAX, 1, + GC0310_V_BLANK_DEFAULT); + + sensor->ctrls.hblank = + v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_HBLANK, + GC0310_H_BLANK_DEFAULT, + GC0310_H_BLANK_DEFAULT, 1, + GC0310_H_BLANK_DEFAULT); + + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + return ret; + + v4l2_ctrl_new_fwnode_properties(hdl, &ctrl_ops, &props); - return hdl->error; + if (hdl->error) + return hdl->error; + + sensor->ctrls.pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sensor->ctrls.link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sensor->ctrls.hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + return 0; } static void gc0310_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc0310_device *dev = to_gc0310_sensor(sd); - - dev_dbg(&client->dev, "gc0310_remove...\n"); + struct gc0310_device *sensor = to_gc0310_sensor(sd); v4l2_async_unregister_subdev(sd); - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrls.handler); - mutex_destroy(&dev->input_lock); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sensor->sd.entity); + v4l2_ctrl_handler_free(&sensor->ctrls.handler); pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) { + gc0310_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + } } -static int gc0310_probe(struct i2c_client *client) +static int gc0310_check_hwcfg(struct device *dev) { + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; struct fwnode_handle *ep_fwnode; - struct gc0310_device *dev; + unsigned long link_freq_bitmap; + u32 mclk; int ret; /* * Sometimes the fwnode graph is initialized by the bridge driver. * Bridge drivers doing this may also add GPIO mappings, wait for this. */ - ep_fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); + ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); if (!ep_fwnode) - return dev_err_probe(&client->dev, -EPROBE_DEFER, "waiting for fwnode graph endpoint\n"); + return dev_err_probe(dev, -EPROBE_DEFER, + "waiting for fwnode graph endpoint\n"); + + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &mclk); + if (ret) { + fwnode_handle_put(ep_fwnode); + return dev_err_probe(dev, ret, + "reading clock-frequency property\n"); + } + + if (mclk != GC0310_MCLK_FREQ) { + fwnode_handle_put(ep_fwnode); + return dev_err_probe(dev, -EINVAL, + "external clock %u is not supported\n", + mclk); + } + ret = v4l2_fwnode_endpoint_alloc_parse(ep_fwnode, &bus_cfg); fwnode_handle_put(ep_fwnode); + if (ret) + return dev_err_probe(dev, ret, "parsing endpoint failed\n"); + + ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + link_freq_menu_items, + ARRAY_SIZE(link_freq_menu_items), + &link_freq_bitmap); + + if (ret == 0 && bus_cfg.bus.mipi_csi2.num_data_lanes != 1) + ret = dev_err_probe(dev, -EINVAL, + "number of CSI2 data lanes %u is not supported\n", + bus_cfg.bus.mipi_csi2.num_data_lanes); + + v4l2_fwnode_endpoint_free(&bus_cfg); + return ret; +} + +static int gc0310_probe(struct i2c_client *client) +{ + struct gc0310_device *sensor; + int ret; - dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) + ret = gc0310_check_hwcfg(&client->dev); + if (ret) + return ret; + + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) return -ENOMEM; - dev->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(dev->reset)) { - return dev_err_probe(&client->dev, PTR_ERR(dev->reset), + sensor->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->reset)) { + return dev_err_probe(&client->dev, PTR_ERR(sensor->reset), "getting reset GPIO\n"); } - dev->powerdown = devm_gpiod_get(&client->dev, "powerdown", GPIOD_OUT_HIGH); - if (IS_ERR(dev->powerdown)) { - return dev_err_probe(&client->dev, PTR_ERR(dev->powerdown), + sensor->powerdown = devm_gpiod_get(&client->dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->powerdown)) { + return dev_err_probe(&client->dev, PTR_ERR(sensor->powerdown), "getting powerdown GPIO\n"); } - mutex_init(&dev->input_lock); - v4l2_i2c_subdev_init(&dev->sd, client, &gc0310_ops); - gc0310_fill_format(&dev->mode.fmt); + v4l2_i2c_subdev_init(&sensor->sd, client, &gc0310_ops); - pm_runtime_set_suspended(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_set_autosuspend_delay(&client->dev, 1000); - pm_runtime_use_autosuspend(&client->dev); + sensor->regmap = devm_cci_regmap_init_i2c(client, 8); + if (IS_ERR(sensor->regmap)) + return PTR_ERR(sensor->regmap); - ret = gc0310_detect(client); - if (ret) { - gc0310_remove(client); - return ret; - } + gc0310_power_on(&client->dev); - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - ret = gc0310_init_controls(dev); - if (ret) { - gc0310_remove(client); - return ret; - } + pm_runtime_set_active(&client->dev); + pm_runtime_get_noresume(&client->dev); + pm_runtime_enable(&client->dev); - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) { - gc0310_remove(client); - return ret; - } + ret = gc0310_detect(sensor); + if (ret) + goto err_power_down; - ret = v4l2_async_register_subdev_sensor(&dev->sd); - if (ret) { - gc0310_remove(client); - return ret; - } + sensor->sd.internal_ops = &gc0310_internal_ops; + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - return 0; -} + ret = gc0310_init_controls(sensor); + if (ret) + goto err_power_down; -static int gc0310_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct gc0310_device *gc0310_dev = to_gc0310_sensor(sd); + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); + if (ret) + goto err_power_down; - gpiod_set_value_cansleep(gc0310_dev->powerdown, 1); - gpiod_set_value_cansleep(gc0310_dev->reset, 1); - return 0; -} + sensor->sd.state_lock = sensor->ctrls.handler.lock; + ret = v4l2_subdev_init_finalize(&sensor->sd); + if (ret) + goto err_power_down; -static int gc0310_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct gc0310_device *gc0310_dev = to_gc0310_sensor(sd); + ret = v4l2_async_register_subdev_sensor(&sensor->sd); + if (ret) + goto err_power_down; - usleep_range(10000, 15000); - gpiod_set_value_cansleep(gc0310_dev->reset, 0); - usleep_range(10000, 15000); - gpiod_set_value_cansleep(gc0310_dev->powerdown, 0); + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put_autosuspend(&client->dev); return 0; + +err_power_down: + pm_runtime_put_noidle(&client->dev); + gc0310_remove(client); + return ret; } -static DEFINE_RUNTIME_DEV_PM_OPS(gc0310_pm_ops, gc0310_suspend, gc0310_resume, NULL); +static DEFINE_RUNTIME_DEV_PM_OPS(gc0310_pm_ops, + gc0310_power_off, gc0310_power_on, NULL); static const struct acpi_device_id gc0310_acpi_match[] = { {"INT0310"}, @@ -708,5 +778,6 @@ static struct i2c_driver gc0310_driver = { module_i2c_driver(gc0310_driver); MODULE_AUTHOR("Lai, Angie <angie.lai@intel.com>"); +MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index 857d7175942cd..6fc39ab95e46f 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -779,8 +779,6 @@ static void gc2235_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct gc2235_device *dev = to_gc2235_sensor(sd); - dev_dbg(&client->dev, "gc2235_remove...\n"); - dev->platform_data->csi_cfg(sd, 0); v4l2_device_unregister_subdev(sd); diff --git a/drivers/staging/media/atomisp/i2c/gc2235.h b/drivers/staging/media/atomisp/i2c/gc2235.h index 6c743a17f198b..7dd9a676fb980 100644 --- a/drivers/staging/media/atomisp/i2c/gc2235.h +++ b/drivers/staging/media/atomisp/i2c/gc2235.h @@ -179,21 +179,21 @@ struct gc2235_write_ctrl { struct gc2235_write_buffer buffer; }; -static struct gc2235_reg const gc2235_stream_on[] = { +static const struct gc2235_reg gc2235_stream_on[] = { { GC2235_8BIT, 0xfe, 0x03}, /* switch to P3 */ { GC2235_8BIT, 0x10, 0x91}, /* start mipi */ { GC2235_8BIT, 0xfe, 0x00}, /* switch to P0 */ { GC2235_TOK_TERM, 0, 0 } }; -static struct gc2235_reg const gc2235_stream_off[] = { +static const struct gc2235_reg gc2235_stream_off[] = { { GC2235_8BIT, 0xfe, 0x03}, /* switch to P3 */ { GC2235_8BIT, 0x10, 0x01}, /* stop mipi */ { GC2235_8BIT, 0xfe, 0x00}, /* switch to P0 */ { GC2235_TOK_TERM, 0, 0 } }; -static struct gc2235_reg const gc2235_init_settings[] = { +static const struct gc2235_reg gc2235_init_settings[] = { /* System */ { GC2235_8BIT, 0xfe, 0x80 }, { GC2235_8BIT, 0xfe, 0x80 }, @@ -268,7 +268,7 @@ static struct gc2235_reg const gc2235_init_settings[] = { * Register settings for various resolution */ #if ENABLE_NON_PREVIEW -static struct gc2235_reg const gc2235_1296_736_30fps[] = { +static const struct gc2235_reg gc2235_1296_736_30fps[] = { { GC2235_8BIT, 0x8b, 0xa0 }, { GC2235_8BIT, 0x8c, 0x02 }, @@ -321,7 +321,7 @@ static struct gc2235_reg const gc2235_1296_736_30fps[] = { { GC2235_TOK_TERM, 0, 0 } }; -static struct gc2235_reg const gc2235_960_640_30fps[] = { +static const struct gc2235_reg gc2235_960_640_30fps[] = { { GC2235_8BIT, 0x8b, 0xa0 }, { GC2235_8BIT, 0x8c, 0x02 }, @@ -373,7 +373,7 @@ static struct gc2235_reg const gc2235_960_640_30fps[] = { }; #endif -static struct gc2235_reg const gc2235_1600_900_30fps[] = { +static const struct gc2235_reg gc2235_1600_900_30fps[] = { { GC2235_8BIT, 0x8b, 0xa0 }, { GC2235_8BIT, 0x8c, 0x02 }, @@ -418,7 +418,7 @@ static struct gc2235_reg const gc2235_1600_900_30fps[] = { { GC2235_TOK_TERM, 0, 0 } }; -static struct gc2235_reg const gc2235_1616_1082_30fps[] = { +static const struct gc2235_reg gc2235_1616_1082_30fps[] = { { GC2235_8BIT, 0x8b, 0xa0 }, { GC2235_8BIT, 0x8c, 0x02 }, @@ -463,7 +463,7 @@ static struct gc2235_reg const gc2235_1616_1082_30fps[] = { { GC2235_TOK_TERM, 0, 0 } }; -static struct gc2235_reg const gc2235_1616_1216_30fps[] = { +static const struct gc2235_reg gc2235_1616_1216_30fps[] = { { GC2235_8BIT, 0x8b, 0xa0 }, { GC2235_8BIT, 0x8c, 0x02 }, diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h index bc36133f37222..00317d1053057 100644 --- a/drivers/staging/media/atomisp/i2c/ov2722.h +++ b/drivers/staging/media/atomisp/i2c/ov2722.h @@ -236,7 +236,7 @@ struct ov2722_write_ctrl { * Register settings for various resolution */ #if 0 -static struct ov2722_reg const ov2722_QVGA_30fps[] = { +static const struct ov2722_reg ov2722_QVGA_30fps[] = { {OV2722_8BIT, 0x3718, 0x10}, {OV2722_8BIT, 0x3702, 0x0c}, {OV2722_8BIT, 0x373a, 0x1c}, @@ -346,7 +346,7 @@ static struct ov2722_reg const ov2722_QVGA_30fps[] = { }; -static struct ov2722_reg const ov2722_480P_30fps[] = { +static const struct ov2722_reg ov2722_480P_30fps[] = { {OV2722_8BIT, 0x3718, 0x10}, {OV2722_8BIT, 0x3702, 0x18}, {OV2722_8BIT, 0x373a, 0x3c}, @@ -455,7 +455,7 @@ static struct ov2722_reg const ov2722_480P_30fps[] = { {OV2722_TOK_TERM, 0, 0}, }; -static struct ov2722_reg const ov2722_VGA_30fps[] = { +static const struct ov2722_reg ov2722_VGA_30fps[] = { {OV2722_8BIT, 0x3718, 0x10}, {OV2722_8BIT, 0x3702, 0x18}, {OV2722_8BIT, 0x373a, 0x3c}, @@ -565,7 +565,7 @@ static struct ov2722_reg const ov2722_VGA_30fps[] = { }; #endif -static struct ov2722_reg const ov2722_1632_1092_30fps[] = { +static const struct ov2722_reg ov2722_1632_1092_30fps[] = { {OV2722_8BIT, 0x3021, 0x03}, /* For stand wait for a whole frame complete.(vblank) */ {OV2722_8BIT, 0x3718, 0x10}, @@ -667,7 +667,7 @@ static struct ov2722_reg const ov2722_1632_1092_30fps[] = { {OV2722_TOK_TERM, 0, 0} }; -static struct ov2722_reg const ov2722_1452_1092_30fps[] = { +static const struct ov2722_reg ov2722_1452_1092_30fps[] = { {OV2722_8BIT, 0x3021, 0x03}, /* For stand wait for a whole frame complete.(vblank) */ {OV2722_8BIT, 0x3718, 0x10}, @@ -769,7 +769,7 @@ static struct ov2722_reg const ov2722_1452_1092_30fps[] = { }; #if 0 -static struct ov2722_reg const ov2722_1M3_30fps[] = { +static const struct ov2722_reg ov2722_1M3_30fps[] = { {OV2722_8BIT, 0x3718, 0x10}, {OV2722_8BIT, 0x3702, 0x24}, {OV2722_8BIT, 0x373a, 0x60}, @@ -877,7 +877,7 @@ static struct ov2722_reg const ov2722_1M3_30fps[] = { }; #endif -static struct ov2722_reg const ov2722_1080p_30fps[] = { +static const struct ov2722_reg ov2722_1080p_30fps[] = { {OV2722_8BIT, 0x3021, 0x03}, /* For stand wait for a whole frame complete.(vblank) */ {OV2722_8BIT, 0x3718, 0x10}, @@ -983,7 +983,7 @@ static struct ov2722_reg const ov2722_1080p_30fps[] = { }; #if 0 /* Currently unused */ -static struct ov2722_reg const ov2722_720p_30fps[] = { +static const struct ov2722_reg ov2722_720p_30fps[] = { {OV2722_8BIT, 0x3021, 0x03}, {OV2722_8BIT, 0x3718, 0x10}, {OV2722_8BIT, 0x3702, 0x24}, diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c index bc97fa2c374c7..be5f37f4a6fd0 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c @@ -387,7 +387,7 @@ static int __destroy_stream(struct atomisp_sub_device *asd, } if (stream_env->stream_state == CSS_STREAM_STARTED) { - timeout = jiffies + msecs_to_jiffies(40); + timeout = jiffies + msecs_to_jiffies(200); while (1) { if (ia_css_stream_has_stopped(stream_env->stream)) break; diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.h b/drivers/staging/media/atomisp/pci/atomisp_csi2.h index bb998c82a438f..ec762f8fb9222 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.h +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.h @@ -19,28 +19,11 @@ #define CSI2_PAD_SOURCE 1 #define CSI2_PADS_NUM 2 -#define CSI2_MAX_ACPI_GPIOS 2u - -struct acpi_device; struct v4l2_device; struct atomisp_device; struct atomisp_sub_device; -struct atomisp_csi2_acpi_gpio_map { - struct acpi_gpio_params params[CSI2_MAX_ACPI_GPIOS]; - struct acpi_gpio_mapping mapping[CSI2_MAX_ACPI_GPIOS + 1]; -}; - -struct atomisp_csi2_acpi_gpio_parsing_data { - struct acpi_device *adev; - struct atomisp_csi2_acpi_gpio_map *map; - u32 settings[CSI2_MAX_ACPI_GPIOS]; - unsigned int settings_count; - unsigned int res_count; - unsigned int map_count; -}; - struct atomisp_mipi_csi2_device { struct v4l2_subdev subdev; struct media_pad pads[CSI2_PADS_NUM]; diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c b/drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c index 6abda358a72f7..2a90f86e515f5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c @@ -13,6 +13,7 @@ #include <linux/clk.h> #include <linux/device.h> #include <linux/dmi.h> +#include <linux/platform_data/x86/int3472.h> #include <linux/property.h> #include <media/ipu-bridge.h> @@ -25,39 +26,6 @@ #define PMC_CLK_RATE_19_2MHZ 19200000 /* - * 79234640-9e10-4fea-a5c1-b5aa8b19756f - * This _DSM GUID returns information about the GPIO lines mapped to a sensor. - * Function number 1 returns a count of the GPIO lines that are mapped. - * Subsequent functions return 32 bit ints encoding information about the GPIO. - */ -static const guid_t intel_sensor_gpio_info_guid = - GUID_INIT(0x79234640, 0x9e10, 0x4fea, - 0xa5, 0xc1, 0xb5, 0xaa, 0x8b, 0x19, 0x75, 0x6f); - -#define INTEL_GPIO_DSM_TYPE_SHIFT 0 -#define INTEL_GPIO_DSM_TYPE_MASK GENMASK(7, 0) -#define INTEL_GPIO_DSM_PIN_SHIFT 8 -#define INTEL_GPIO_DSM_PIN_MASK GENMASK(15, 8) -#define INTEL_GPIO_DSM_SENSOR_ON_VAL_SHIFT 24 -#define INTEL_GPIO_DSM_SENSOR_ON_VAL_MASK GENMASK(31, 24) - -#define INTEL_GPIO_DSM_TYPE(x) \ - (((x) & INTEL_GPIO_DSM_TYPE_MASK) >> INTEL_GPIO_DSM_TYPE_SHIFT) -#define INTEL_GPIO_DSM_PIN(x) \ - (((x) & INTEL_GPIO_DSM_PIN_MASK) >> INTEL_GPIO_DSM_PIN_SHIFT) -#define INTEL_GPIO_DSM_SENSOR_ON_VAL(x) \ - (((x) & INTEL_GPIO_DSM_SENSOR_ON_VAL_MASK) >> INTEL_GPIO_DSM_SENSOR_ON_VAL_SHIFT) - -/* - * 822ace8f-2814-4174-a56b-5f029fe079ee - * This _DSM GUID returns a string from the sensor device, which acts as a - * module identifier. - */ -static const guid_t intel_sensor_module_guid = - GUID_INIT(0x822ace8f, 0x2814, 0x4174, - 0xa5, 0x6b, 0x5f, 0x02, 0x9f, 0xe0, 0x79, 0xee); - -/* * dc2f6c4f-045b-4f1d-97b9-882a6860a4be * This _DSM GUID returns a package with n*2 strings, with each set of 2 strings * forming a key, value pair for settings like e.g. "CsiLanes" = "1". @@ -323,196 +291,45 @@ static int atomisp_csi2_get_port(struct acpi_device *adev, int clock_num) return gmin_cfg_get_int(adev, "CsiPort", port); } -/* Note this always returns 1 to continue looping so that res_count is accurate */ -static int atomisp_csi2_handle_acpi_gpio_res(struct acpi_resource *ares, void *_data) -{ - struct atomisp_csi2_acpi_gpio_parsing_data *data = _data; - struct acpi_resource_gpio *agpio; - const char *name; - bool active_low; - unsigned int i; - u32 settings = 0; - u16 pin; - - if (!acpi_gpio_get_io_resource(ares, &agpio)) - return 1; /* Not a GPIO, continue the loop */ - - data->res_count++; - - pin = agpio->pin_table[0]; - for (i = 0; i < data->settings_count; i++) { - if (INTEL_GPIO_DSM_PIN(data->settings[i]) == pin) { - settings = data->settings[i]; - break; - } - } - - if (i == data->settings_count) { - acpi_handle_warn(data->adev->handle, - "%s: Could not find DSM GPIO settings for pin %u\n", - dev_name(&data->adev->dev), pin); - return 1; - } - - switch (INTEL_GPIO_DSM_TYPE(settings)) { - case 0: - name = "reset-gpios"; - break; - case 1: - name = "powerdown-gpios"; - break; - default: - acpi_handle_warn(data->adev->handle, "%s: Unknown GPIO type 0x%02lx for pin %u\n", - dev_name(&data->adev->dev), - INTEL_GPIO_DSM_TYPE(settings), pin); - return 1; - } - - /* - * Both reset and power-down need to be logical false when the sensor - * is on (sensor should not be in reset and not be powered-down). So - * when the sensor-on-value (which is the physical pin value) is high, - * then the signal is active-low. - */ - active_low = INTEL_GPIO_DSM_SENSOR_ON_VAL(settings); - - i = data->map_count; - if (i == CSI2_MAX_ACPI_GPIOS) - return 1; - - /* res_count is already incremented */ - data->map->params[i].crs_entry_index = data->res_count - 1; - data->map->params[i].active_low = active_low; - data->map->mapping[i].name = name; - data->map->mapping[i].data = &data->map->params[i]; - data->map->mapping[i].size = 1; - data->map_count++; - - acpi_handle_info(data->adev->handle, "%s: %s crs %d %s pin %u active-%s\n", - dev_name(&data->adev->dev), name, - data->res_count - 1, agpio->resource_source.string_ptr, - pin, active_low ? "low" : "high"); - - return 1; -} - /* - * Helper function to create an ACPI GPIO lookup table for sensor reset and - * powerdown signals on Intel Bay Trail (BYT) and Cherry Trail (CHT) devices, - * including setting the correct polarity for the GPIO. - * - * This uses the "79234640-9e10-4fea-a5c1-b5aa8b19756f" DSM method directly - * on the sensor device's ACPI node. This is different from later Intel - * hardware which has a separate INT3472 acpi_device with this info. - * - * This function must be called before creating the sw-noded describing - * the fwnode graph endpoint. And sensor drivers used on these devices - * must return -EPROBE_DEFER when there is no endpoint description yet. - * Together this guarantees that the GPIO lookups are in place before - * the sensor driver tries to get GPIOs with gpiod_get(). + * Alloc and fill an int3472_discrete_device struct so that we can re-use + * the INT3472 sensor GPIO mapping code. * - * Note this code uses the same DSM GUID as the int3472_gpio_guid in - * the INT3472 discrete.c code and there is some overlap, but there are - * enough differences that it is difficult to share the code. + * This gets called from ipu_bridge_init() which runs only once per boot, + * the created faux int3472 device is leaked on purpose to keep the created + * GPIO mappings around permanently. */ static int atomisp_csi2_add_gpio_mappings(struct acpi_device *adev) { - struct atomisp_csi2_acpi_gpio_parsing_data data = { }; - LIST_HEAD(resource_list); - union acpi_object *obj; - unsigned int i, j; + struct int3472_discrete_device *int3472; int ret; - obj = acpi_evaluate_dsm_typed(adev->handle, &intel_sensor_module_guid, - 0x00, 1, NULL, ACPI_TYPE_STRING); - if (obj) { - acpi_handle_info(adev->handle, "%s: Sensor module id: '%s'\n", - dev_name(&adev->dev), obj->string.pointer); - ACPI_FREE(obj); - } + /* Max num GPIOs we've seen plus a terminator */ + int3472 = kzalloc(struct_size(int3472, gpios.table, INT3472_MAX_SENSOR_GPIOS + 1), + GFP_KERNEL); + if (!int3472) + return -ENOMEM; /* - * First get the GPIO-settings count and then get count GPIO-settings - * values. Note the order of these may differ from the order in which - * the GPIOs are listed on the ACPI resources! So we first store them all - * and then enumerate the ACPI resources and match them up by pin number. + * On atomisp the _DSM to get the GPIO type must be made on the sensor + * adev, rather than on a separate INT3472 adev. */ - obj = acpi_evaluate_dsm_typed(adev->handle, - &intel_sensor_gpio_info_guid, 0x00, 1, - NULL, ACPI_TYPE_INTEGER); - if (!obj) { - acpi_handle_err(adev->handle, "%s: No _DSM entry for GPIO pin count\n", - dev_name(&adev->dev)); - return -EIO; - } - - data.settings_count = obj->integer.value; - ACPI_FREE(obj); + int3472->adev = adev; + int3472->dev = &adev->dev; + int3472->sensor = adev; - if (data.settings_count > CSI2_MAX_ACPI_GPIOS) { - acpi_handle_err(adev->handle, "%s: Too many GPIOs %u > %u\n", - dev_name(&adev->dev), data.settings_count, - CSI2_MAX_ACPI_GPIOS); - return -EOVERFLOW; + int3472->sensor_name = kasprintf(GFP_KERNEL, I2C_DEV_NAME_FORMAT, acpi_dev_name(adev)); + if (!int3472->sensor_name) { + kfree(int3472); + return -ENOMEM; } - for (i = 0; i < data.settings_count; i++) { - /* - * i + 2 because the index of this _DSM function is 1-based - * and the first function is just a count. - */ - obj = acpi_evaluate_dsm_typed(adev->handle, - &intel_sensor_gpio_info_guid, - 0x00, i + 2, - NULL, ACPI_TYPE_INTEGER); - if (!obj) { - acpi_handle_err(adev->handle, "%s: No _DSM entry for pin %u\n", - dev_name(&adev->dev), i); - return -EIO; - } - - data.settings[i] = obj->integer.value; - ACPI_FREE(obj); + ret = int3472_discrete_parse_crs(int3472); + if (ret) { + int3472_discrete_cleanup(int3472); + kfree(int3472); } - /* Since we match up by pin-number the pin-numbers must be unique */ - for (i = 0; i < data.settings_count; i++) { - for (j = i + 1; j < data.settings_count; j++) { - if (INTEL_GPIO_DSM_PIN(data.settings[i]) != - INTEL_GPIO_DSM_PIN(data.settings[j])) - continue; - - acpi_handle_err(adev->handle, "%s: Duplicate pin number %lu\n", - dev_name(&adev->dev), - INTEL_GPIO_DSM_PIN(data.settings[i])); - return -EIO; - } - } - - data.map = kzalloc(sizeof(*data.map), GFP_KERNEL); - if (!data.map) - return -ENOMEM; - - /* Now parse the ACPI resources and build the lookup table */ - data.adev = adev; - ret = acpi_dev_get_resources(adev, &resource_list, - atomisp_csi2_handle_acpi_gpio_res, &data); - if (ret < 0) - return ret; - - acpi_dev_free_resource_list(&resource_list); - - if (data.map_count != data.settings_count || - data.res_count != data.settings_count) - acpi_handle_warn(adev->handle, "%s: ACPI GPIO resources vs DSM GPIO-info count mismatch (dsm: %d res: %d map %d\n", - dev_name(&adev->dev), data.settings_count, - data.res_count, data.map_count); - - ret = acpi_dev_add_driver_gpios(adev, data.map->mapping); - if (ret) - acpi_handle_err(adev->handle, "%s: Error adding driver GPIOs: %d\n", - dev_name(&adev->dev), ret); - return ret; } diff --git a/drivers/staging/media/atomisp/pci/atomisp_drvfs.c b/drivers/staging/media/atomisp/pci/atomisp_drvfs.c deleted file mode 100644 index 31c82c3c0d33f..0000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp_drvfs.c +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Support for atomisp driver sysfs interface - * - * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - */ - -#include <linux/device.h> -#include <linux/err.h> -#include <linux/kernel.h> - -#include "atomisp_compat.h" -#include "atomisp_internal.h" -#include "atomisp_ioctl.h" -#include "atomisp_drvfs.h" -#include "hmm/hmm.h" -#include "ia_css_debug.h" - -#define OPTION_BIN_LIST BIT(0) -#define OPTION_BIN_RUN BIT(1) -#define OPTION_VALID (OPTION_BIN_LIST | OPTION_BIN_RUN) - -/* - * dbgopt: iunit debug option: - * bit 0: binary list - * bit 1: running binary - * bit 2: memory statistic - */ -static unsigned int dbgopt = OPTION_BIN_LIST; - -static inline int iunit_dump_dbgopt(struct atomisp_device *isp, - unsigned int opt) -{ - int ret = 0; - - if (opt & OPTION_VALID) { - if (opt & OPTION_BIN_LIST) { - ret = atomisp_css_dump_blob_infor(isp); - if (ret) { - dev_err(isp->dev, "%s dump blob infor err[ret:%d]\n", - __func__, ret); - goto opt_err; - } - } - - if (opt & OPTION_BIN_RUN) { - if (isp->asd.streaming) { - atomisp_css_dump_sp_raw_copy_linecount(true); - atomisp_css_debug_dump_isp_binary(); - } else { - ret = -EPERM; - dev_err(isp->dev, "%s dump running bin err[ret:%d]\n", - __func__, ret); - goto opt_err; - } - } - } else { - ret = -EINVAL; - dev_err(isp->dev, "%s dump nothing[ret=%d]\n", __func__, ret); - } - -opt_err: - return ret; -} - -static ssize_t dbglvl_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - unsigned int dbglvl = ia_css_debug_get_dtrace_level(); - - return sysfs_emit(buf, "dtrace level:%u\n", dbglvl); -} - -static ssize_t dbglvl_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t size) -{ - unsigned int dbglvl; - int ret; - - ret = kstrtouint(buf, 10, &dbglvl); - if (ret) - return ret; - - if (dbglvl < 1 || dbglvl > 9) - return -ERANGE; - - ia_css_debug_set_dtrace_level(dbglvl); - return size; -} -static DEVICE_ATTR_RW(dbglvl); - -static ssize_t dbgfun_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - unsigned int dbgfun = atomisp_get_css_dbgfunc(); - - return sysfs_emit(buf, "dbgfun opt:%u\n", dbgfun); -} - -static ssize_t dbgfun_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t size) -{ - struct atomisp_device *isp = dev_get_drvdata(dev); - unsigned int opt; - int ret; - - ret = kstrtouint(buf, 10, &opt); - if (ret) - return ret; - - return atomisp_set_css_dbgfunc(isp, opt); -} -static DEVICE_ATTR_RW(dbgfun); - -static ssize_t dbgopt_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return sysfs_emit(buf, "option:0x%x\n", dbgopt); -} - -static ssize_t dbgopt_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t size) -{ - struct atomisp_device *isp = dev_get_drvdata(dev); - unsigned int opt; - int ret; - - ret = kstrtouint(buf, 10, &opt); - if (ret) - return ret; - - dbgopt = opt; - ret = iunit_dump_dbgopt(isp, dbgopt); - if (ret) - return ret; - - return size; -} -static DEVICE_ATTR_RW(dbgopt); - -static struct attribute *dbg_attrs[] = { - &dev_attr_dbglvl.attr, - &dev_attr_dbgfun.attr, - &dev_attr_dbgopt.attr, - NULL -}; - -static const struct attribute_group dbg_attr_group = { - .attrs = dbg_attrs, -}; - -const struct attribute_group *dbg_attr_groups[] = { - &dbg_attr_group, - NULL -}; diff --git a/drivers/staging/media/atomisp/pci/atomisp_drvfs.h b/drivers/staging/media/atomisp/pci/atomisp_drvfs.h deleted file mode 100644 index 46ad59b8df284..0000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp_drvfs.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Support for atomisp driver sysfs interface. - * - * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - */ - -#ifndef __ATOMISP_DRVFS_H__ -#define __ATOMISP_DRVFS_H__ - -#include <linux/sysfs.h> - -extern const struct attribute_group *dbg_attr_groups[]; - -#endif /* __ATOMISP_DRVFS_H__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index 57da7ddb15033..c7aef066f209d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -234,9 +234,6 @@ static int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd, if (WARN_ON(css_pipe_id >= IA_CSS_PIPE_ID_NUM)) return -EINVAL; - if (pipe->stopping) - return -EINVAL; - space = ATOMISP_CSS_Q_DEPTH - atomisp_buffers_in_css(pipe); while (space--) { struct ia_css_frame *frame; @@ -367,7 +364,7 @@ static void atomisp_buf_queue(struct vb2_buffer *vb) mutex_lock(&asd->isp->mutex); ret = atomisp_pipe_check(pipe, false); - if (ret || pipe->stopping) { + if (ret) { spin_lock_irqsave(&pipe->irq_lock, irqflags); atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); spin_unlock_irqrestore(&pipe->irq_lock, irqflags); diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 5f59519ac8e28..964cc3bcc0ac0 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -1272,14 +1272,15 @@ static int gmin_get_config_var(struct device *maindev, if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) status = efi.get_variable(var16, &GMIN_CFG_VAR_EFI_GUID, NULL, (unsigned long *)out_len, out); - if (status == EFI_SUCCESS) + if (status == EFI_SUCCESS) { dev_info(maindev, "found EFI entry for '%s'\n", var8); - else if (is_gmin) + return 0; + } + if (is_gmin) dev_info(maindev, "Failed to find EFI gmin variable %s\n", var8); else dev_info(maindev, "Failed to find EFI variable %s\n", var8); - - return ret; + return -ENOENT; } int gmin_get_var_int(struct device *dev, bool is_gmin, const char *var, int def) diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index 97d99bed15601..bb8b2f2213b08 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -856,6 +856,62 @@ static void atomisp_dma_burst_len_cfg(struct atomisp_sub_device *asd) atomisp_css2_hw_store_32(DMA_BURST_SIZE_REG, 0x00); } +static void atomisp_stop_stream(struct atomisp_video_pipe *pipe, + bool stop_sensor, enum vb2_buffer_state state) +{ + struct atomisp_sub_device *asd = pipe->asd; + struct atomisp_device *isp = asd->isp; + struct pci_dev *pdev = to_pci_dev(isp->dev); + unsigned long flags; + int ret; + + spin_lock_irqsave(&isp->lock, flags); + asd->streaming = false; + spin_unlock_irqrestore(&isp->lock, flags); + + atomisp_clear_css_buffer_counters(asd); + atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false); + + atomisp_css_stop(asd, false); + + atomisp_subdev_cleanup_pending_events(asd); + + if (stop_sensor) { + ret = v4l2_subdev_call(isp->inputs[asd->input_curr].csi_remote_source, + video, s_stream, 0); + if (ret) + dev_warn(isp->dev, "Stopping sensor stream failed: %d\n", ret); + } + + /* Disable the CSI interface on ANN B0/K0 */ + if (isp->media_dev.hw_revision >= ((ATOMISP_HW_REVISION_ISP2401 << + ATOMISP_HW_REVISION_SHIFT) | ATOMISP_HW_STEPPING_B0)) { + pci_write_config_word(pdev, MRFLD_PCI_CSI_CONTROL, + isp->saved_regs.csi_control & ~MRFLD_PCI_CSI_CONTROL_CSI_READY); + } + + if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_LOW, false)) + dev_warn(isp->dev, "DFS failed.\n"); + + /* + * ISP work around, need to reset ISP to allow next stream on to work. + * Streams have already been destroyed by atomisp_css_stop(). + * Disable PUNIT/ISP acknowledge/handshake - SRSE=3 and then reset. + */ + pci_write_config_dword(pdev, PCI_I_CONTROL, + isp->saved_regs.i_control | MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK); + atomisp_reset(isp); + + atomisp_flush_video_pipe(pipe, state, false); + + /* Streams were destroyed by atomisp_css_stop(), recreate them. */ + ret = atomisp_create_pipes_stream(&isp->asd); + if (ret) + dev_warn(isp->dev, "Recreating streams failed: %d\n", ret); + + media_pipeline_stop(&asd->video_out.vdev.entity.pads[0]); +} + int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) { struct atomisp_video_pipe *pipe = vq_to_pipe(vq); @@ -910,6 +966,7 @@ int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) ret = atomisp_css_start(asd); if (ret) { atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_QUEUED, true); + media_pipeline_stop(&asd->video_out.vdev.entity.pads[0]); goto out_unlock; } @@ -949,11 +1006,7 @@ int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) video, s_stream, 1); if (ret) { dev_err(isp->dev, "Starting sensor stream failed: %d\n", ret); - spin_lock_irqsave(&isp->lock, irqflags); - asd->streaming = false; - spin_unlock_irqrestore(&isp->lock, irqflags); - ret = -EINVAL; - goto out_unlock; + atomisp_stop_stream(pipe, false, VB2_BUF_STATE_QUEUED); } out_unlock: @@ -964,74 +1017,12 @@ out_unlock: void atomisp_stop_streaming(struct vb2_queue *vq) { struct atomisp_video_pipe *pipe = vq_to_pipe(vq); - struct atomisp_sub_device *asd = pipe->asd; - struct atomisp_device *isp = asd->isp; - struct pci_dev *pdev = to_pci_dev(isp->dev); - unsigned long flags; - int ret; + struct atomisp_device *isp = pipe->asd->isp; dev_dbg(isp->dev, "Stop stream\n"); mutex_lock(&isp->mutex); - /* - * There is no guarantee that the buffers queued to / owned by the ISP - * will properly be returned to the queue when stopping. Set a flag to - * avoid new buffers getting queued and then wait for all the current - * buffers to finish. - */ - pipe->stopping = true; - mutex_unlock(&isp->mutex); - /* wait max 1 second */ - ret = wait_event_timeout(pipe->vb_queue.done_wq, - atomisp_buffers_in_css(pipe) == 0, HZ); - mutex_lock(&isp->mutex); - pipe->stopping = false; - if (ret == 0) - dev_warn(isp->dev, "Warning timeout waiting for CSS to return buffers\n"); - - spin_lock_irqsave(&isp->lock, flags); - asd->streaming = false; - spin_unlock_irqrestore(&isp->lock, flags); - - atomisp_clear_css_buffer_counters(asd); - atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false); - - atomisp_css_stop(asd, false); - - atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_ERROR, true); - - atomisp_subdev_cleanup_pending_events(asd); - - ret = v4l2_subdev_call(isp->inputs[asd->input_curr].csi_remote_source, - video, s_stream, 0); - if (ret) - dev_warn(isp->dev, "Stopping sensor stream failed: %d\n", ret); - - /* Disable the CSI interface on ANN B0/K0 */ - if (isp->media_dev.hw_revision >= ((ATOMISP_HW_REVISION_ISP2401 << - ATOMISP_HW_REVISION_SHIFT) | ATOMISP_HW_STEPPING_B0)) { - pci_write_config_word(pdev, MRFLD_PCI_CSI_CONTROL, - isp->saved_regs.csi_control & ~MRFLD_PCI_CSI_CONTROL_CSI_READY); - } - - if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_LOW, false)) - dev_warn(isp->dev, "DFS failed.\n"); - - /* - * ISP work around, need to reset ISP to allow next stream on to work. - * Streams have already been destroyed by atomisp_css_stop(). - * Disable PUNIT/ISP acknowledge/handshake - SRSE=3 and then reset. - */ - pci_write_config_dword(pdev, PCI_I_CONTROL, - isp->saved_regs.i_control | MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK); - atomisp_reset(isp); - - /* Streams were destroyed by atomisp_css_stop(), recreate them. */ - ret = atomisp_create_pipes_stream(&isp->asd); - if (ret) - dev_warn(isp->dev, "Recreating streams failed: %d\n", ret); - - media_pipeline_stop(&asd->video_out.vdev.entity.pads[0]); + atomisp_stop_stream(pipe, true, VB2_BUF_STATE_ERROR); mutex_unlock(&isp->mutex); } diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h index bd1a198cda30e..e1d0168cb91d3 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h @@ -57,9 +57,6 @@ struct atomisp_video_pipe { /* Filled through atomisp_get_css_frame_info() on queue setup */ struct ia_css_frame_info frame_info; - /* Set from streamoff to disallow queuing further buffers in CSS */ - bool stopping; - /* * irq_lock is used to protect video buffer state change operations and * also to make activeq and capq operations atomic. diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index 0bd0bfded4af1..900a67552d6a0 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -29,7 +29,6 @@ #include "atomisp_internal.h" #include "atomisp-regs.h" #include "atomisp_dfs_tables.h" -#include "atomisp_drvfs.h" #include "hmm/hmm.h" #include "atomisp_trace_event.h" @@ -1497,9 +1496,6 @@ static const struct pci_device_id atomisp_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, atomisp_pci_tbl); static struct pci_driver atomisp_pci_driver = { - .driver = { - .dev_groups = dbg_attr_groups, - }, .name = "atomisp-isp2", .id_table = atomisp_pci_tbl, .probe = atomisp_pci_probe, @@ -1513,3 +1509,4 @@ MODULE_AUTHOR("Xiaolin Zhang <xiaolin.zhang@intel.com>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Intel ATOM Platform ISP Driver"); MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); +MODULE_IMPORT_NS("INTEL_INT3472_DISCRETE"); diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h index 6d45d0d8d060b..2cb5c986790a8 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h @@ -10,14 +10,9 @@ /* Override the definition of max/min from Linux kernel */ #include <linux/minmax.h> -/* force a value to a lower even value */ -#define EVEN_FLOOR(x) ((x) & ~1) - #define CEIL_DIV(a, b) (((b) != 0) ? ((a) + (b) - 1) / (b) : 0) #define CEIL_MUL(a, b) (CEIL_DIV(a, b) * (b)) -#define CEIL_MUL2(a, b) (((a) + (b) - 1) & ~((b) - 1)) #define CEIL_SHIFT(a, b) (((a) + (1 << (b)) - 1) >> (b)) -#define CEIL_SHIFT_MUL(a, b) (CEIL_SHIFT(a, b) << (b)) /* * For SP and ISP, SDK provides the definition of OP_std_modadd. diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm.c b/drivers/staging/media/atomisp/pci/hmm/hmm.c index 84102c3aaf975..f998b57f90c4d 100644 --- a/drivers/staging/media/atomisp/pci/hmm/hmm.c +++ b/drivers/staging/media/atomisp/pci/hmm/hmm.c @@ -28,88 +28,6 @@ struct hmm_bo_device bo_device; static ia_css_ptr dummy_ptr = mmgr_EXCEPTION; static bool hmm_initialized; -/* - * p: private - * v: vmalloc - */ -static const char hmm_bo_type_string[] = "pv"; - -static ssize_t bo_show(struct device *dev, struct device_attribute *attr, - char *buf, struct list_head *bo_list, bool active) -{ - ssize_t ret = 0; - struct hmm_buffer_object *bo; - unsigned long flags; - int i; - long total[HMM_BO_LAST] = { 0 }; - long count[HMM_BO_LAST] = { 0 }; - int index1 = 0; - int index2 = 0; - - ret = scnprintf(buf, PAGE_SIZE, "type pgnr\n"); - if (ret <= 0) - return 0; - - index1 += ret; - - spin_lock_irqsave(&bo_device.list_lock, flags); - list_for_each_entry(bo, bo_list, list) { - if ((active && (bo->status & HMM_BO_ALLOCED)) || - (!active && !(bo->status & HMM_BO_ALLOCED))) { - ret = scnprintf(buf + index1, PAGE_SIZE - index1, - "%c %d\n", - hmm_bo_type_string[bo->type], bo->pgnr); - - total[bo->type] += bo->pgnr; - count[bo->type]++; - if (ret > 0) - index1 += ret; - } - } - spin_unlock_irqrestore(&bo_device.list_lock, flags); - - for (i = 0; i < HMM_BO_LAST; i++) { - if (count[i]) { - ret = scnprintf(buf + index1 + index2, - PAGE_SIZE - index1 - index2, - "%ld %c buffer objects: %ld KB\n", - count[i], hmm_bo_type_string[i], - total[i] * 4); - if (ret > 0) - index2 += ret; - } - } - - /* Add trailing zero, not included by scnprintf */ - return index1 + index2 + 1; -} - -static ssize_t active_bo_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return bo_show(dev, attr, buf, &bo_device.entire_bo_list, true); -} - -static ssize_t free_bo_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return bo_show(dev, attr, buf, &bo_device.entire_bo_list, false); -} - - -static DEVICE_ATTR_RO(active_bo); -static DEVICE_ATTR_RO(free_bo); - -static struct attribute *sysfs_attrs_ctrl[] = { - &dev_attr_active_bo.attr, - &dev_attr_free_bo.attr, - NULL -}; - -static struct attribute_group atomisp_attribute_group[] = { - {.attrs = sysfs_attrs_ctrl }, -}; - int hmm_init(void) { int ret; @@ -130,14 +48,6 @@ int hmm_init(void) */ dummy_ptr = hmm_alloc(1); - if (!ret) { - ret = sysfs_create_group(&atomisp_dev->kobj, - atomisp_attribute_group); - if (ret) - dev_err(atomisp_dev, - "%s Failed to create sysfs\n", __func__); - } - return ret; } @@ -145,7 +55,6 @@ void hmm_cleanup(void) { if (dummy_ptr == mmgr_EXCEPTION) return; - sysfs_remove_group(&atomisp_dev->kobj, atomisp_attribute_group); /* free dummy memory first */ hmm_free(dummy_ptr); diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c index 224ca8d42721a..5d0cd5260d3a2 100644 --- a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c +++ b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c @@ -37,8 +37,6 @@ static int __bo_init(struct hmm_bo_device *bdev, struct hmm_buffer_object *bo, unsigned int pgnr) { check_bodev_null_return(bdev, -EINVAL); - var_equal_return(hmm_bo_device_inited(bdev), 0, -EINVAL, - "hmm_bo_device not inited yet.\n"); /* prevent zero size buffer object */ if (pgnr == 0) { dev_err(atomisp_dev, "0 size buffer is not allowed.\n"); @@ -341,7 +339,6 @@ int hmm_bo_device_init(struct hmm_bo_device *bdev, spin_lock_init(&bdev->list_lock); mutex_init(&bdev->rbtree_mutex); - bdev->flag = HMM_BO_DEVICE_INITED; INIT_LIST_HEAD(&bdev->entire_bo_list); bdev->allocated_rbtree = RB_ROOT; @@ -376,6 +373,8 @@ int hmm_bo_device_init(struct hmm_bo_device *bdev, __bo_insert_to_free_rbtree(&bdev->free_rbtree, bo); + bdev->flag = HMM_BO_DEVICE_INITED; + return 0; } diff --git a/drivers/staging/media/atomisp/pci/ia_css_pipe.h b/drivers/staging/media/atomisp/pci/ia_css_pipe.h index c97d2ae356fd2..77072694eb422 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_pipe.h +++ b/drivers/staging/media/atomisp/pci/ia_css_pipe.h @@ -102,8 +102,6 @@ struct ia_css_yuvpp_settings { struct osys_object; struct ia_css_pipe { - /* TODO: Remove stop_requested and use stop_requested in the pipeline */ - bool stop_requested; struct ia_css_pipe_config config; struct ia_css_pipe_extra_config extra_config; struct ia_css_pipe_info info; diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h index 6e573ceaa9ea2..bc2a78dff004e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h @@ -11,9 +11,11 @@ * CSS-API header file for Advanced Noise Reduction kernel v1 */ +#include <linux/math.h> + /* Application specific DMA settings */ #define ANR_BPP 10 -#define ANR_ELEMENT_BITS ((CEIL_DIV(ANR_BPP, 8)) * 8) +#define ANR_ELEMENT_BITS round_up(ANR_BPP, 8) /* Advanced Noise Reduction configuration. * This is also known as Low-Light. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2_param.h index 099f32b8de1a6..b1bbc283e367c 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2_param.h @@ -7,6 +7,8 @@ #ifndef __IA_CSS_DPC2_PARAM_H #define __IA_CSS_DPC2_PARAM_H +#include <linux/math.h> + #include "type_support.h" #include "vmem.h" /* for VMEM_ARRAY*/ @@ -19,12 +21,12 @@ /* 3 lines state per color plane input_line_state */ #define DPC2_STATE_INPUT_BUFFER_HEIGHT (3 * NUM_PLANES) /* Each plane has width equal to half frame line */ -#define DPC2_STATE_INPUT_BUFFER_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) +#define DPC2_STATE_INPUT_BUFFER_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) /* 1 line state per color plane for local deviation state*/ #define DPC2_STATE_LOCAL_DEVIATION_BUFFER_HEIGHT (1 * NUM_PLANES) /* Each plane has width equal to half frame line */ -#define DPC2_STATE_LOCAL_DEVIATION_BUFFER_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) +#define DPC2_STATE_LOCAL_DEVIATION_BUFFER_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) /* MINMAX state buffer stores 1 full input line (GR-R color line) */ #define DPC2_STATE_SECOND_MINMAX_BUFFER_HEIGHT 1 diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs.host.c index 30c84639d7e88..e9d6dd0bbfe28 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs.host.c @@ -141,10 +141,10 @@ convert_coords_to_ispparams( /* similar to topleft_y calculation, but round up if ymax * has any fraction bits */ - bottom_y = CEIL_DIV(ymax, 1 << DVS_COORD_FRAC_BITS); + bottom_y = DIV_ROUND_UP(ymax, BIT(DVS_COORD_FRAC_BITS)); s.in_block_height = bottom_y - topleft_y + dvs_interp_envelope; - bottom_x = CEIL_DIV(xmax, 1 << DVS_COORD_FRAC_BITS); + bottom_x = DIV_ROUND_UP(xmax, BIT(DVS_COORD_FRAC_BITS)); s.in_block_width = bottom_x - topleft_x + dvs_interp_envelope; topleft_x_frac = topleft_x << (DVS_COORD_FRAC_BITS); diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_param.h index df87770446dd6..a24eef965f16e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_param.h @@ -7,6 +7,8 @@ #ifndef __IA_CSS_EED1_8_PARAM_H #define __IA_CSS_EED1_8_PARAM_H +#include <linux/math.h> + #include "type_support.h" #include "vmem.h" /* needed for VMEM_ARRAY */ @@ -35,35 +37,35 @@ #define EED1_8_STATE_INPUT_BUFFER_HEIGHT (5 * NUM_PLANES) /* Each plane has width equal to half frame line */ -#define EED1_8_STATE_INPUT_BUFFER_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) +#define EED1_8_STATE_INPUT_BUFFER_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) /* 1 line state per color plane LD_H state */ #define EED1_8_STATE_LD_H_HEIGHT (1 * NUM_PLANES) -#define EED1_8_STATE_LD_H_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) +#define EED1_8_STATE_LD_H_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) /* 1 line state per color plane LD_V state */ #define EED1_8_STATE_LD_V_HEIGHT (1 * NUM_PLANES) -#define EED1_8_STATE_LD_V_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) +#define EED1_8_STATE_LD_V_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) /* 1 line (single plane) state for D_Hr state */ #define EED1_8_STATE_D_HR_HEIGHT 1 -#define EED1_8_STATE_D_HR_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) +#define EED1_8_STATE_D_HR_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) /* 1 line (single plane) state for D_Hb state */ #define EED1_8_STATE_D_HB_HEIGHT 1 -#define EED1_8_STATE_D_HB_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) +#define EED1_8_STATE_D_HB_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) /* 2 lines (single plane) state for D_Vr state */ #define EED1_8_STATE_D_VR_HEIGHT 2 -#define EED1_8_STATE_D_VR_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) +#define EED1_8_STATE_D_VR_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) /* 2 line (single plane) state for D_Vb state */ #define EED1_8_STATE_D_VB_HEIGHT 2 -#define EED1_8_STATE_D_VB_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) +#define EED1_8_STATE_D_VB_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) /* 2 lines state for R and B (= 2 planes) rb_zipped_state */ #define EED1_8_STATE_RB_ZIPPED_HEIGHT (2 * 2) -#define EED1_8_STATE_RB_ZIPPED_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) +#define EED1_8_STATE_RB_ZIPPED_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) #if EED1_8_FC_ENABLE_MEDIAN /* 1 full input line (GR-R color line) for Yc state */ @@ -72,11 +74,11 @@ /* 1 line state per color plane Cg_state */ #define EED1_8_STATE_CG_HEIGHT (1 * NUM_PLANES) -#define EED1_8_STATE_CG_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) +#define EED1_8_STATE_CG_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) /* 1 line state per color plane Co_state */ #define EED1_8_STATE_CO_HEIGHT (1 * NUM_PLANES) -#define EED1_8_STATE_CO_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) +#define EED1_8_STATE_CO_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) /* 1 full input line (GR-R color line) for AbsK state */ #define EED1_8_STATE_ABSK_HEIGHT 1 diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn.host.c index b34feba5340bc..e701b7e41ef4e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn.host.c @@ -4,6 +4,8 @@ * Copyright (c) 2015, Intel Corporation. */ +#include <linux/math.h> + #include <assert_support.h> #include <ia_css_frame_public.h> #include <ia_css_frame.h> @@ -71,9 +73,9 @@ int ia_css_fpn_configure(const struct ia_css_binary *binary, &my_info }; - my_info.res.width = CEIL_DIV(info->res.width, 2); /* Packed by 2x */ + my_info.res.width = DIV_ROUND_UP(info->res.width, 2); /* Packed by 2x */ my_info.res.height = info->res.height; - my_info.padded_width = CEIL_DIV(info->padded_width, 2); /* Packed by 2x */ + my_info.padded_width = DIV_ROUND_UP(info->padded_width, 2); /* Packed by 2x */ my_info.format = info->format; my_info.raw_bit_depth = FPN_BITS_PER_PIXEL; my_info.raw_bayer_order = info->raw_bayer_order; diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc_param.h index 61e9c04d25157..b49761ad39cad 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc_param.h @@ -22,7 +22,7 @@ struct sh_css_isp_sc_params { * vec_slice is used for 2 adjacent vectors of shading gains. * The number of shift times by vec_slice is 8. * Max grid cell bqs to support the shading table centerting: N = 32 - * CEIL_DIV(N-1, ISP_SLICE_NELEMS) = CEIL_DIV(31, 4) = 8 + * DIV_ROUND_UP(N-1, ISP_SLICE_NELEMS) = DIV_ROUND_UP(31, 4) = 8 */ #define SH_CSS_SC_INTERPED_GAIN_HOR_SLICE_TIMES 8 diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf.host.c index 127f12ba22144..3c675063c4a7e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf.host.c @@ -91,8 +91,7 @@ configure_kernel( unsigned int vf_log_ds = 0; /* First compute value */ - if (vf_info) - { + if (vf_info) { err = sh_css_vf_downscale_log2(out_info, vf_info, &vf_log_ds); if (err) return err; diff --git a/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h b/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h index c7ade6ce6c68a..6a0257359e695 100644 --- a/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h +++ b/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h @@ -8,9 +8,10 @@ Copyright (c) 2010 - 2015, Intel Corporation. #ifndef _INPUT_BUF_ISP_H_ #define _INPUT_BUF_ISP_H_ +#include <linux/math.h> + /* Temporary include, since IA_CSS_BINARY_MODE_COPY is still needed */ #include "sh_css_defs.h" -#include "isp_const.h" /* MAX_VECTORS_PER_INPUT_LINE */ #define INPUT_BUF_HEIGHT 2 /* double buffer */ #define INPUT_BUF_LINES 2 @@ -22,7 +23,8 @@ Copyright (c) 2010 - 2015, Intel Corporation. /* In continuous mode, the input buffer must be a fixed size for all binaries * and at a fixed address since it will be used by the SP. */ #define EXTRA_INPUT_VECTORS 2 /* For left padding */ -#define MAX_VECTORS_PER_INPUT_LINE_CONT (CEIL_DIV(SH_CSS_MAX_SENSOR_WIDTH, ISP_NWAY) + EXTRA_INPUT_VECTORS) +#define MAX_VECTORS_PER_INPUT_LINE_CONT \ + (DIV_ROUND_UP(SH_CSS_MAX_SENSOR_WIDTH, ISP_NWAY) + EXTRA_INPUT_VECTORS) /* The input buffer should be on a fixed address in vmem, for continuous capture */ #define INPUT_BUF_ADDR 0x0 diff --git a/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_const.h b/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_const.h deleted file mode 100644 index b767b0d35bb49..0000000000000 --- a/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_const.h +++ /dev/null @@ -1,157 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/** -Support for Intel Camera Imaging ISP subsystem. -Copyright (c) 2010 - 2015, Intel Corporation. - -*/ - -#ifndef _COMMON_ISP_CONST_H_ -#define _COMMON_ISP_CONST_H_ - -/*#include "isp.h"*/ /* ISP_VEC_NELEMS */ - -/* Binary independent constants */ - -#ifndef NO_HOIST -# define NO_HOIST HIVE_ATTRIBUTE((no_hoist)) -#endif - -#define NO_HOIST_CSE HIVE_ATTRIBUTE((no_hoist, no_cse)) - -#define UNION struct /* Union constructors not allowed in C++ */ - -#define XMEM_WIDTH_BITS HIVE_ISP_DDR_WORD_BITS -#define XMEM_SHORTS_PER_WORD (HIVE_ISP_DDR_WORD_BITS / 16) -#define XMEM_INTS_PER_WORD (HIVE_ISP_DDR_WORD_BITS / 32) -#define XMEM_POW2_BYTES_PER_WORD HIVE_ISP_DDR_WORD_BYTES - -#define BITS8_ELEMENTS_PER_XMEM_ADDR CEIL_DIV(XMEM_WIDTH_BITS, 8) -#define BITS16_ELEMENTS_PER_XMEM_ADDR CEIL_DIV(XMEM_WIDTH_BITS, 16) - -#define ISP_NWAY_LOG2 6 - -/* ***************************** - * ISP input/output buffer sizes - * ****************************/ -/* input image */ -#define INPUT_BUF_DMA_HEIGHT 2 -#define INPUT_BUF_HEIGHT 2 /* double buffer */ -#define OUTPUT_BUF_DMA_HEIGHT 2 -#define OUTPUT_BUF_HEIGHT 2 /* double buffer */ -#define OUTPUT_NUM_TRANSFERS 4 - -/* GDC accelerator: Up/Down Scaling */ -/* These should be moved to the gdc_defs.h in the device */ -#define UDS_SCALING_N HRT_GDC_N -/* AB: This should cover the zooming up to 16MP */ -#define UDS_MAX_OXDIM 5000 -/* We support maximally 2 planes with different parameters - - luma and chroma (YUV420) */ -#define UDS_MAX_PLANES 2 -#define UDS_BLI_BLOCK_HEIGHT 2 -#define UDS_BCI_BLOCK_HEIGHT 4 -#define UDS_BLI_INTERP_ENVELOPE 1 -#define UDS_BCI_INTERP_ENVELOPE 3 -#define UDS_MAX_ZOOM_FAC 64 -/* Make it always one FPGA vector. - Four FPGA vectors are required and - four of them fit in one ASIC vector.*/ -#define UDS_MAX_CHUNKS 16 - -#define ISP_LEFT_PADDING _ISP_LEFT_CROP_EXTRA(ISP_LEFT_CROPPING) -#define ISP_LEFT_PADDING_VECS CEIL_DIV(ISP_LEFT_PADDING, ISP_VEC_NELEMS) -/* in case of continuous the croppong of the current binary doesn't matter for the buffer calculation, but the cropping of the sp copy should be used */ -#define ISP_LEFT_PADDING_CONT _ISP_LEFT_CROP_EXTRA(SH_CSS_MAX_LEFT_CROPPING) -#define ISP_LEFT_PADDING_VECS_CONT CEIL_DIV(ISP_LEFT_PADDING_CONT, ISP_VEC_NELEMS) - -#define CEIL_ROUND_DIV_STRIPE(width, stripe, padding) \ - CEIL_MUL(padding + CEIL_DIV(width - padding, stripe), ((ENABLE_RAW_BINNING || ENABLE_FIXED_BAYER_DS) ? 4 : 2)) - -/* output (Y,U,V) image, 4:2:0 */ -#define MAX_VECTORS_PER_LINE \ - CEIL_ROUND_DIV_STRIPE(CEIL_DIV(ISP_MAX_INTERNAL_WIDTH, ISP_VEC_NELEMS), \ - ISP_NUM_STRIPES, \ - ISP_LEFT_PADDING_VECS) - -/* - * ITERATOR_VECTOR_INCREMENT' explanation: - * when striping an even number of iterations, one of the stripes is - * one iteration wider than the other to account for overlap - * so the calc for the output buffer vmem size is: - * ((width[vectors]/num_of_stripes) + 2[vectors]) - */ -#define MAX_VECTORS_PER_OUTPUT_LINE \ - CEIL_DIV(CEIL_DIV(ISP_MAX_OUTPUT_WIDTH, ISP_NUM_STRIPES) + ISP_LEFT_PADDING, ISP_VEC_NELEMS) - -/* Must be even due to interlaced bayer input */ -#define MAX_VECTORS_PER_INPUT_LINE CEIL_MUL((CEIL_DIV(ISP_MAX_INPUT_WIDTH, ISP_VEC_NELEMS) + ISP_LEFT_PADDING_VECS), 2) -#define MAX_VECTORS_PER_INPUT_STRIPE CEIL_ROUND_DIV_STRIPE(MAX_VECTORS_PER_INPUT_LINE, \ - ISP_NUM_STRIPES, \ - ISP_LEFT_PADDING_VECS) - -/* Add 2 for left croppping */ -#define MAX_SP_RAW_COPY_VECTORS_PER_INPUT_LINE (CEIL_DIV(ISP_MAX_INPUT_WIDTH, ISP_VEC_NELEMS) + 2) - -#define MAX_VECTORS_PER_BUF_LINE \ - (MAX_VECTORS_PER_LINE + DUMMY_BUF_VECTORS) -#define MAX_VECTORS_PER_BUF_INPUT_LINE \ - (MAX_VECTORS_PER_INPUT_STRIPE + DUMMY_BUF_VECTORS) -#define MAX_OUTPUT_Y_FRAME_WIDTH \ - (MAX_VECTORS_PER_LINE * ISP_VEC_NELEMS) -#define MAX_OUTPUT_Y_FRAME_SIMDWIDTH \ - MAX_VECTORS_PER_LINE -#define MAX_OUTPUT_C_FRAME_WIDTH \ - (MAX_OUTPUT_Y_FRAME_WIDTH / 2) -#define MAX_OUTPUT_C_FRAME_SIMDWIDTH \ - CEIL_DIV(MAX_OUTPUT_C_FRAME_WIDTH, ISP_VEC_NELEMS) - -/* should be even */ -#define NO_CHUNKING (OUTPUT_NUM_CHUNKS == 1) - -#define MAX_VECTORS_PER_CHUNK \ - (NO_CHUNKING ? MAX_VECTORS_PER_LINE \ - : 2 * CEIL_DIV(MAX_VECTORS_PER_LINE, \ - 2 * OUTPUT_NUM_CHUNKS)) - -#define MAX_C_VECTORS_PER_CHUNK \ - (MAX_VECTORS_PER_CHUNK / 2) - -/* should be even */ -#define MAX_VECTORS_PER_OUTPUT_CHUNK \ - (NO_CHUNKING ? MAX_VECTORS_PER_OUTPUT_LINE \ - : 2 * CEIL_DIV(MAX_VECTORS_PER_OUTPUT_LINE, \ - 2 * OUTPUT_NUM_CHUNKS)) - -#define MAX_C_VECTORS_PER_OUTPUT_CHUNK \ - (MAX_VECTORS_PER_OUTPUT_CHUNK / 2) - -/* should be even */ -#define MAX_VECTORS_PER_INPUT_CHUNK \ - (INPUT_NUM_CHUNKS == 1 ? MAX_VECTORS_PER_INPUT_STRIPE \ - : 2 * CEIL_DIV(MAX_VECTORS_PER_INPUT_STRIPE, \ - 2 * OUTPUT_NUM_CHUNKS)) - -#define DEFAULT_C_SUBSAMPLING 2 - -/****** DMA buffer properties */ - -#define RAW_BUF_LINES ((ENABLE_RAW_BINNING || ENABLE_FIXED_BAYER_DS) ? 4 : 2) - -/* [isp vmem] table size[vectors] per line per color (GR,R,B,GB), - multiples of NWAY */ -#define ISP2400_SCTBL_VECTORS_PER_LINE_PER_COLOR \ - CEIL_DIV(SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR, ISP_VEC_NELEMS) -#define ISP2401_SCTBL_VECTORS_PER_LINE_PER_COLOR \ - CEIL_DIV(SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR, ISP_VEC_NELEMS) -/* [isp vmem] table size[vectors] per line for 4colors (GR,R,B,GB), - multiples of NWAY */ -#define SCTBL_VECTORS_PER_LINE \ - (SCTBL_VECTORS_PER_LINE_PER_COLOR * IA_CSS_SC_NUM_COLORS) - -/*************/ - -/* Format for fixed primaries */ - -#define ISP_FIXED_PRIMARY_FORMAT IA_CSS_FRAME_FORMAT_NV12 - -#endif /* _COMMON_ISP_CONST_H_ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c index 84220359c9576..b411ca2f415e0 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c +++ b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c @@ -51,7 +51,6 @@ #include "sp.h" #include "isp.h" #include "type_support.h" -#include "math_support.h" /* CEIL_DIV */ #include "input_system.h" /* input_formatter_reg_load */ #include "ia_css_tagger_common.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c b/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c index 4f610f57e6c11..2cb96f9a60308 100644 --- a/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c +++ b/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c @@ -4,15 +4,16 @@ * Copyright (c) 2015, Intel Corporation. */ -#include "hmm.h" +#include <linux/bitops.h> +#include <linux/math.h> -#include "ia_css_frame.h" -#include <math_support.h> #include "assert_support.h" +#include "atomisp_internal.h" +#include "hmm.h" #include "ia_css_debug.h" +#include "ia_css_frame.h" #include "isp.h" #include "sh_css_internal.h" -#include "atomisp_internal.h" #define NV12_TILEY_TILE_WIDTH 128 #define NV12_TILEY_TILE_HEIGHT 32 @@ -459,15 +460,16 @@ static void frame_init_single_plane(struct ia_css_frame *frame, unsigned int stride; stride = subpixels_per_line * bytes_per_pixel; - /* Frame height needs to be even number - needed by hw ISYS2401 - In case of odd number, round up to even. - Images won't be impacted by this round up, - only needed by jpeg/embedded data. - As long as buffer allocation and release are using data_bytes, - there won't be memory leak. */ - frame->data_bytes = stride * CEIL_MUL2(height, 2); + /* + * Frame height needs to be even number - needed by hw ISYS2401. + * In case of odd number, round up to even. + * Images won't be impacted by this round up, + * only needed by jpeg/embedded data. + * As long as buffer allocation and release are using data_bytes, + * there won't be memory leak. + */ + frame->data_bytes = stride * round_up(height, 2); frame_init_plane(plane, subpixels_per_line, stride, height, 0); - return; } static void frame_init_raw_single_plane( @@ -486,7 +488,6 @@ static void frame_init_raw_single_plane( HIVE_ISP_DDR_WORD_BITS / bits_per_pixel); frame->data_bytes = stride * height; frame_init_plane(plane, subpixels_per_line, stride, height, 0); - return; } static void frame_init_nv_planes(struct ia_css_frame *frame, @@ -690,7 +691,7 @@ ia_css_elems_bytes_from_info(const struct ia_css_frame_info *info) if (info->format == IA_CSS_FRAME_FORMAT_RAW || (info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED)) { if (info->raw_bit_depth) - return CEIL_DIV(info->raw_bit_depth, 8); + return BITS_TO_BYTES(info->raw_bit_depth); else return 2; /* bytes per pixel */ } diff --git a/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c b/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c index d57ffb335fc0c..50b0b31d734a9 100644 --- a/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c +++ b/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c @@ -4,9 +4,9 @@ * Copyright (c) 2010 - 2015, Intel Corporation. */ -#include "system_global.h" -#include <linux/kernel.h> +#include <linux/math.h> +#include "system_global.h" #include "ia_css_ifmtr.h" #include <math_support.h> @@ -149,10 +149,9 @@ int ia_css_ifmtr_configure(struct ia_css_stream_config *config, left_padding = 2 * ISP_VEC_NELEMS - config->left_padding; if (left_padding) { - num_vectors = CEIL_DIV(cropped_width + left_padding, - ISP_VEC_NELEMS); + num_vectors = DIV_ROUND_UP(cropped_width + left_padding, ISP_VEC_NELEMS); } else { - num_vectors = CEIL_DIV(cropped_width, ISP_VEC_NELEMS); + num_vectors = DIV_ROUND_UP(cropped_width, ISP_VEC_NELEMS); num_vectors *= buffer_height; /* todo: in case of left padding, num_vectors is vectors per line, @@ -305,7 +304,7 @@ int ia_css_ifmtr_configure(struct ia_css_stream_config *config, if ((!binary) || config->continuous) /* !binary -> sp raw copy pipe */ buffer_height *= 2; - vectors_per_line = CEIL_DIV(cropped_width, ISP_VEC_NELEMS); + vectors_per_line = DIV_ROUND_UP(cropped_width, ISP_VEC_NELEMS); vectors_per_line = CEIL_MUL(vectors_per_line, deinterleaving); break; case ATOMISP_INPUT_FORMAT_RAW_14: diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c index b5395aea89fc7..e6c11d5f77b41 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c @@ -808,7 +808,7 @@ static bool calculate_isys2401_dma_port_cfg( cfg->elements = HIVE_ISP_DDR_WORD_BITS / bits_per_pixel; cfg->cropping = 0; - cfg->width = CEIL_DIV(cfg->stride, HIVE_ISP_DDR_WORD_BYTES); + cfg->width = DIV_ROUND_UP(cfg->stride, HIVE_ISP_DDR_WORD_BYTES); return true; } diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h index 316eaa2070ea7..8b7cbf31a1a2a 100644 --- a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h +++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h @@ -34,7 +34,6 @@ struct ia_css_pipeline_stage { struct ia_css_pipeline { enum ia_css_pipe_id pipe_id; u8 pipe_num; - bool stop_requested; struct ia_css_pipeline_stage *stages; struct ia_css_pipeline_stage *current_stage; unsigned int num_stages; diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c b/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c index aabebe61ec779..cb8d652227a7b 100644 --- a/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c +++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c @@ -198,7 +198,6 @@ int ia_css_pipeline_request_stop(struct ia_css_pipeline *pipeline) ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipeline_request_stop() enter: pipeline=%p\n", pipeline); - pipeline->stop_requested = true; /* Send stop event to the sp*/ /* This needs improvement, stop on all the pipes available @@ -663,7 +662,6 @@ static void pipeline_init_defaults( pipeline->pipe_id = pipe_id; pipeline->stages = NULL; - pipeline->stop_requested = false; pipeline->current_stage = NULL; memcpy(&pipeline->in_frame, &ia_css_default_frame, diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 5a8e8e67aa138..73bd87f43a8c2 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -2002,10 +2002,6 @@ ia_css_uninit(void) sh_css_params_free_default_gdc_lut(); - /* TODO: JB: implement decent check and handling of freeing mipi frames */ - if (!mipi_is_free()) - dev_warn(atomisp_dev, "mipi frames are not freed.\n"); - /* cleanup generic data */ sh_css_params_uninit(); ia_css_refcount_uninit(); @@ -3743,23 +3739,6 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe, case IA_CSS_BUFFER_TYPE_INPUT_FRAME: case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME: case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME: - if (pipe && pipe->stop_requested) { - if (!IS_ISP2401) { - /* - * free mipi frames only for old input - * system for 2401 it is done in - * ia_css_stream_destroy call - */ - return_err = free_mipi_frames(pipe); - if (return_err) { - IA_CSS_LOG("free_mipi_frames() failed"); - IA_CSS_LEAVE_ERR(return_err); - return return_err; - } - } - pipe->stop_requested = false; - } - fallthrough; case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME: case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME: frame = (struct ia_css_frame *)HOST_ADDRESS(ddr_buffer.kernel_ptr); @@ -4095,8 +4074,6 @@ sh_css_pipe_start(struct ia_css_stream *stream) return err; } - pipe->stop_requested = false; - switch (pipe_id) { case IA_CSS_PIPE_ID_PREVIEW: err = preview_start(pipe); @@ -4120,19 +4097,15 @@ sh_css_pipe_start(struct ia_css_stream *stream) for (i = 1; i < stream->num_pipes && 0 == err ; i++) { switch (stream->pipes[i]->mode) { case IA_CSS_PIPE_ID_PREVIEW: - stream->pipes[i]->stop_requested = false; err = preview_start(stream->pipes[i]); break; case IA_CSS_PIPE_ID_VIDEO: - stream->pipes[i]->stop_requested = false; err = video_start(stream->pipes[i]); break; case IA_CSS_PIPE_ID_CAPTURE: - stream->pipes[i]->stop_requested = false; err = capture_start(stream->pipes[i]); break; case IA_CSS_PIPE_ID_YUVPP: - stream->pipes[i]->stop_requested = false; err = yuvpp_start(stream->pipes[i]); break; default: diff --git a/drivers/staging/media/atomisp/pci/sh_css_defs.h b/drivers/staging/media/atomisp/pci/sh_css_defs.h index 51491dfe05cc9..7bfeeb8cf053d 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_defs.h +++ b/drivers/staging/media/atomisp/pci/sh_css_defs.h @@ -7,12 +7,12 @@ #ifndef _SH_CSS_DEFS_H_ #define _SH_CSS_DEFS_H_ +#include <linux/math.h> + #include "isp.h" /*#include "vamem.h"*/ /* Cannot include for VAMEM properties this file is visible on ISP -> pipeline generator */ -#include "math_support.h" /* max(), min, etc etc */ - /* ID's for refcount */ #define IA_CSS_REFCOUNT_PARAM_SET_POOL 0xCAFE0001 #define IA_CSS_REFCOUNT_PARAM_BUFFER 0xCAFE0002 @@ -182,7 +182,7 @@ RGB[0,8191],coef[-8192,8191] -> RGB[0,8191] The ISP firmware needs these rules to be applied at pre-processor time, that's why these are macros, not functions. */ #define _ISP_BQS(num) ((num) / 2) -#define _ISP_VECS(width) CEIL_DIV(width, ISP_VEC_NELEMS) +#define _ISP_VECS(width) DIV_ROUND_UP(width, ISP_VEC_NELEMS) #define ISP_BQ_GRID_WIDTH(elements_per_line, deci_factor_log2) \ CEIL_SHIFT(elements_per_line / 2, deci_factor_log2) @@ -194,9 +194,9 @@ RGB[0,8191],coef[-8192,8191] -> RGB[0,8191] /* The morphing table is similar to the shading table in the sense that we have 1 more value than we have cells in the grid. */ #define _ISP_MORPH_TABLE_WIDTH(int_width) \ - (CEIL_DIV(int_width, SH_CSS_MORPH_TABLE_GRID) + 1) + (DIV_ROUND_UP(int_width, SH_CSS_MORPH_TABLE_GRID) + 1) #define _ISP_MORPH_TABLE_HEIGHT(int_height) \ - (CEIL_DIV(int_height, SH_CSS_MORPH_TABLE_GRID) + 1) + (DIV_ROUND_UP(int_height, SH_CSS_MORPH_TABLE_GRID) + 1) #define _ISP_MORPH_TABLE_ALIGNED_WIDTH(width) \ CEIL_MUL(_ISP_MORPH_TABLE_WIDTH(width), \ SH_CSS_MORPH_TABLE_ELEMS_PER_DDR_WORD) @@ -298,7 +298,7 @@ RGB[0,8191],coef[-8192,8191] -> RGB[0,8191] c_subsampling, \ num_chunks, \ pipelining) \ - CEIL_MUL2(CEIL_MUL2(MAX(__ISP_PADDED_OUTPUT_WIDTH(out_width, \ + round_up(round_up(MAX(__ISP_PADDED_OUTPUT_WIDTH(out_width, \ dvs_env_width, \ left_crop), \ __ISP_MIN_INTERNAL_WIDTH(num_chunks, \ diff --git a/drivers/staging/media/atomisp/pci/sh_css_internal.h b/drivers/staging/media/atomisp/pci/sh_css_internal.h index 7b34835857484..9155a83fcc03d 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_internal.h +++ b/drivers/staging/media/atomisp/pci/sh_css_internal.h @@ -8,6 +8,7 @@ #define _SH_CSS_INTERNAL_H_ #include <linux/build_bug.h> +#include <linux/math.h> #include <linux/stdarg.h> #include <system_global.h> @@ -95,7 +96,6 @@ * the SIZE_OF_XXX macro of the corresponding struct. If they are not * equal, functionality will break. */ -#define CALC_ALIGNMENT_MEMBER(x, y) (CEIL_MUL(x, y) - x) #define SIZE_OF_HRT_VADDRESS sizeof(hive_uint32) /* Number of SP's */ @@ -704,13 +704,11 @@ struct sh_css_hmm_buffer { /* Do not use sizeof(uint64_t) since that does not exist of SP */ #define SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT \ - (SIZE_OF_PAYLOAD_UNION + \ - CALC_ALIGNMENT_MEMBER(SIZE_OF_PAYLOAD_UNION, 8) + \ + (round_up(SIZE_OF_PAYLOAD_UNION, 8) + \ 8 + \ 8 + \ SIZE_OF_IA_CSS_TIME_MEAS_STRUCT + \ - SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT + \ - CALC_ALIGNMENT_MEMBER(SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT, 8)) + round_up(SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT, 8)) static_assert(sizeof(struct sh_css_hmm_buffer) == SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT); diff --git a/drivers/staging/media/atomisp/pci/sh_css_mipi.c b/drivers/staging/media/atomisp/pci/sh_css_mipi.c index 42f14ed853e1c..971b685cdb58b 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_mipi.c +++ b/drivers/staging/media/atomisp/pci/sh_css_mipi.c @@ -185,17 +185,6 @@ mipi_init(void) ref_count_mipi_allocation[i] = 0; } -bool mipi_is_free(void) -{ - unsigned int i; - - for (i = 0; i < N_CSI_PORTS; i++) - if (ref_count_mipi_allocation[i]) - return false; - - return true; -} - /* * @brief Calculate the required MIPI buffer sizes. * Based on the stream configuration, calculate the diff --git a/drivers/staging/media/atomisp/pci/sh_css_mipi.h b/drivers/staging/media/atomisp/pci/sh_css_mipi.h index 6f7389f44baa7..b3887ee3c75a9 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_mipi.h +++ b/drivers/staging/media/atomisp/pci/sh_css_mipi.h @@ -14,8 +14,6 @@ void mipi_init(void); -bool mipi_is_free(void); - int allocate_mipi_frames(struct ia_css_pipe *pipe, struct ia_css_stream_info *info); diff --git a/drivers/staging/media/atomisp/pci/sh_css_param_dvs.h b/drivers/staging/media/atomisp/pci/sh_css_param_dvs.h index b7057887adea6..b31a0d4e8acb8 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_param_dvs.h +++ b/drivers/staging/media/atomisp/pci/sh_css_param_dvs.h @@ -7,6 +7,8 @@ #ifndef _SH_CSS_PARAMS_DVS_H_ #define _SH_CSS_PARAMS_DVS_H_ +#include <linux/math.h> + #include <math_support.h> #include <ia_css_types.h> #include "gdc_global.h" /* gdc_warp_param_mem_t */ @@ -20,22 +22,20 @@ /* ISP2400 */ /* horizontal 64x64 blocks round up to DVS_BLOCKDIM_X, make even */ -#define DVS_NUM_BLOCKS_X(X) (CEIL_MUL(CEIL_DIV((X), DVS_BLOCKDIM_X), 2)) +#define DVS_NUM_BLOCKS_X(X) round_up(DIV_ROUND_UP((X), DVS_BLOCKDIM_X), 2) +#define DVS_NUM_BLOCKS_X_CHROMA(X) DIV_ROUND_UP((X), DVS_BLOCKDIM_X) /* ISP2400 */ /* vertical 64x64 blocks round up to DVS_BLOCKDIM_Y */ -#define DVS_NUM_BLOCKS_Y(X) (CEIL_DIV((X), DVS_BLOCKDIM_Y_LUMA)) -#define DVS_NUM_BLOCKS_X_CHROMA(X) (CEIL_DIV((X), DVS_BLOCKDIM_X)) -#define DVS_NUM_BLOCKS_Y_CHROMA(X) (CEIL_DIV((X), DVS_BLOCKDIM_Y_CHROMA)) +#define DVS_NUM_BLOCKS_Y(X) DIV_ROUND_UP((X), DVS_BLOCKDIM_Y_LUMA) +#define DVS_NUM_BLOCKS_Y_CHROMA(X) DIV_ROUND_UP((X), DVS_BLOCKDIM_Y_CHROMA) -#define DVS_TABLE_IN_BLOCKDIM_X_LUMA(X) (DVS_NUM_BLOCKS_X(X) + 1) /* N blocks have N + 1 set of coords */ -#define DVS_TABLE_IN_BLOCKDIM_X_CHROMA(X) (DVS_NUM_BLOCKS_X_CHROMA(X) + 1) +/* N blocks have N + 1 set of coords */ +#define DVS_TABLE_IN_BLOCKDIM_X_LUMA(X) (DVS_NUM_BLOCKS_X(X) + 1) +#define DVS_TABLE_IN_BLOCKDIM_X_CHROMA(X) (DVS_NUM_BLOCKS_X_CHROMA(X) + 1) #define DVS_TABLE_IN_BLOCKDIM_Y_LUMA(X) (DVS_NUM_BLOCKS_Y(X) + 1) #define DVS_TABLE_IN_BLOCKDIM_Y_CHROMA(X) (DVS_NUM_BLOCKS_Y_CHROMA(X) + 1) -#define DVS_ENVELOPE_X(X) (((X) == 0) ? (DVS_ENV_MIN_X) : (X)) -#define DVS_ENVELOPE_Y(X) (((X) == 0) ? (DVS_ENV_MIN_Y) : (X)) - #define DVS_COORD_FRAC_BITS (10) /* ISP2400 */ @@ -43,8 +43,8 @@ #define XMEM_ALIGN_LOG2 (5) -#define DVS_6AXIS_COORDS_ELEMS CEIL_MUL(sizeof(gdc_warp_param_mem_t) \ - , HIVE_ISP_DDR_WORD_BYTES) +#define DVS_6AXIS_COORDS_ELEMS \ + round_up(sizeof(gdc_warp_param_mem_t), HIVE_ISP_DDR_WORD_BYTES) /* currently we only support two output with the same resolution, output 0 is th default one. */ #define DVS_6AXIS_BYTES(binary) \ diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index 0d4a936ad80f5..11d62313c9086 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -4,6 +4,8 @@ * Copyright (c) 2015, Intel Corporation. */ +#include <linux/math.h> + #include "gdc_device.h" /* gdc_lut_store(), ... */ #include "isp.h" /* ISP_VEC_ELEMBITS */ #include "vamem.h" @@ -21,8 +23,6 @@ #include "platform_support.h" #include "assert_support.h" -#include "misc_support.h" /* NOT_USED */ -#include "math_support.h" /* max(), min() EVEN_FLOOR()*/ #include "ia_css_stream.h" #include "sh_css_params_internal.h" @@ -4042,10 +4042,10 @@ sh_css_update_uds_and_crop_info( } /* Must enforce that the crop position is even */ - crop_x = EVEN_FLOOR(crop_x); - crop_y = EVEN_FLOOR(crop_y); - uds_xc = EVEN_FLOOR(uds_xc); - uds_yc = EVEN_FLOOR(uds_yc); + crop_x = round_down(crop_x, 2); + crop_y = round_down(crop_y, 2); + uds_xc = round_down(uds_xc, 2); + uds_yc = round_down(uds_yc, 2); uds->xc = (uint16_t)uds_xc; uds->yc = (uint16_t)uds_yc; diff --git a/drivers/staging/media/imx/imx-media-csc-scaler.c b/drivers/staging/media/imx/imx-media-csc-scaler.c index e5e08c6f79f22..19fd31cb9bb03 100644 --- a/drivers/staging/media/imx/imx-media-csc-scaler.c +++ b/drivers/staging/media/imx/imx-media-csc-scaler.c @@ -912,7 +912,7 @@ imx_media_csc_scaler_device_init(struct imx_media_dev *md) return &priv->vdev; err_m2m: - video_set_drvdata(vfd, NULL); + video_device_release(vfd); err_vfd: kfree(priv); return ERR_PTR(ret); diff --git a/drivers/staging/media/ipu7/Kconfig b/drivers/staging/media/ipu7/Kconfig new file mode 100644 index 0000000000000..7d831ba7501d4 --- /dev/null +++ b/drivers/staging/media/ipu7/Kconfig @@ -0,0 +1,19 @@ +config VIDEO_INTEL_IPU7 + tristate "Intel IPU7 driver" + depends on ACPI || COMPILE_TEST + depends on VIDEO_DEV + depends on X86 && HAS_DMA + depends on IPU_BRIDGE || !IPU_BRIDGE + depends on PCI + select AUXILIARY_BUS + select IOMMU_IOVA + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select VIDEOBUF2_DMA_SG + select V4L2_FWNODE + help + This is the 7th Gen Intel Image Processing Unit, found in Intel SoCs + and used for capturing images and video from camera sensors. + + To compile this driver, say Y here! It contains 2 modules - + intel_ipu7 and intel_ipu7_isys. diff --git a/drivers/staging/media/ipu7/Makefile b/drivers/staging/media/ipu7/Makefile new file mode 100644 index 0000000000000..6d2aec219e659 --- /dev/null +++ b/drivers/staging/media/ipu7/Makefile @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2017 - 2025 Intel Corporation. + +intel-ipu7-objs += ipu7.o \ + ipu7-bus.o \ + ipu7-dma.o \ + ipu7-mmu.o \ + ipu7-buttress.o \ + ipu7-cpd.o \ + ipu7-syscom.o \ + ipu7-boot.o + +obj-$(CONFIG_VIDEO_INTEL_IPU7) += intel-ipu7.o + +intel-ipu7-isys-objs += ipu7-isys.o \ + ipu7-isys-csi2.o \ + ipu7-isys-csi-phy.o \ + ipu7-fw-isys.o \ + ipu7-isys-video.o \ + ipu7-isys-queue.o \ + ipu7-isys-subdev.o + +obj-$(CONFIG_VIDEO_INTEL_IPU7) += intel-ipu7-isys.o diff --git a/drivers/staging/media/ipu7/TODO b/drivers/staging/media/ipu7/TODO new file mode 100644 index 0000000000000..7fbc37059adfa --- /dev/null +++ b/drivers/staging/media/ipu7/TODO @@ -0,0 +1,28 @@ +This is a list of things that need to be done to get this driver out of the +staging directory. + +- ABI headers cleanup + Cleanup the firmware ABI headers + +- Add metadata capture support + The IPU7 hardware should support metadata capture, but it is not + fully verified with IPU7 firmware ABI so far, need to add the metadata + capture support. + +- Refine CSI2 PHY code + Refine the ipu7-isys-csi2-phy.c, move the hardware specific variant + into structure, clarify and explain the PHY registers to make it more + readable. + +- Work with the common IPU module + Sakari commented much of the driver code is the same than the IPU6 driver. + IPU7 driver is expected to work with the common IPU module in future. + +- Register definition cleanup + Cleanup the register definitions - remove some unnecessary definitions + remove 'U' suffix for hexadecimal and decimal values and add IPU7 prefix + for IPU7 specific registers. + Some ISYS IO sub-blocks register definitions are offset values from + specific sub-block base, but it is not clear and well suited for driver + to use, need to update the register definitions to make it more clear + and readable. diff --git a/drivers/staging/media/ipu7/abi/ipu7_fw_boot_abi.h b/drivers/staging/media/ipu7/abi/ipu7_fw_boot_abi.h new file mode 100644 index 0000000000000..a1519c4fe6618 --- /dev/null +++ b/drivers/staging/media/ipu7/abi/ipu7_fw_boot_abi.h @@ -0,0 +1,163 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 - 2025 Intel Corporation + */ + +#ifndef IPU7_FW_BOOT_ABI_H +#define IPU7_FW_BOOT_ABI_H + +#include "ipu7_fw_common_abi.h" +#include "ipu7_fw_syscom_abi.h" + +#define IA_GOFO_FWLOG_SEVERITY_CRIT (0U) +#define IA_GOFO_FWLOG_SEVERITY_ERROR (1U) +#define IA_GOFO_FWLOG_SEVERITY_WARNING (2U) +#define IA_GOFO_FWLOG_SEVERITY_INFO (3U) +#define IA_GOFO_FWLOG_SEVERITY_DEBUG (4U) +#define IA_GOFO_FWLOG_SEVERITY_VERBOSE (5U) +#define IA_GOFO_FWLOG_MAX_LOGGER_SOURCES (64U) + +#define LOGGER_CONFIG_CHANNEL_ENABLE_HWPRINTF_BITMASK BIT(0) +#define LOGGER_CONFIG_CHANNEL_ENABLE_SYSCOM_BITMASK BIT(1) +#define LOGGER_CONFIG_CHANNEL_ENABLE_ALL_BITMASK \ + (LOGGER_CONFIG_CHANNEL_ENABLE_HWPRINTF_BITMASK | \ + LOGGER_CONFIG_CHANNEL_ENABLE_SYSCOM_BITMASK) + +struct ia_gofo_logger_config { + u8 use_source_severity; + u8 source_severity[IA_GOFO_FWLOG_MAX_LOGGER_SOURCES]; + u8 use_channels_enable_bitmask; + u8 channels_enable_bitmask; + u8 padding[1]; + ia_gofo_addr_t hw_printf_buffer_base_addr; + u32 hw_printf_buffer_size_bytes; +}; + +#pragma pack(push, 1) + +#define IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX_PER_APP \ + ((u32)IA_GOFO_FW_BOOT_ID_MAX) +#define IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_IS_OFFSET (0U) +#define IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_PS_OFFSET \ + ((IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_IS_OFFSET) + \ + (u32)(IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX_PER_APP)) +#define IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_PRIMARY_OFFSET (0U) +#define IA_GOFO_CCG_IPU_BUTTRESS_FW_BOOT_PARAMS_SECONDARY_OFFSET (0x3000U / 4U) +#define IA_GOFO_HKR_IPU_BUTTRESS_FW_BOOT_PARAMS_SECONDARY_OFFSET \ + (IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX_PER_APP * 2U) +#define IA_GOFO_HKR_HIF_BUTTRESS_FW_BOOT_PARAMS_SECONDARY_OFFSET \ + (IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX_PER_APP) +#define IA_GOFO_CCG_IPU_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX \ + (IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX_PER_APP * 4U) +#define IA_GOFO_HKR_IPU_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX \ + (IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX_PER_APP * 4U) + +#define IA_GOFO_BOOT_RESERVED_SIZE (58U) +#define IA_GOFO_BOOT_SECONDARY_RESERVED_SIZE (IA_GOFO_BOOT_RESERVED_SIZE) +#define IA_GOFO_BOOT_SECONDARY_RESERVED_FIELDS \ + (sizeof(ia_gofo_addr_t) + sizeof(ia_gofo_addr_t) + sizeof(u32)) + +enum ia_gofo_buttress_reg_id { + IA_GOFO_FW_BOOT_CONFIG_ID = 0, + IA_GOFO_FW_BOOT_STATE_ID = 1, + IA_GOFO_FW_BOOT_RESERVED1_ID = IA_GOFO_FW_BOOT_STATE_ID, + IA_GOFO_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID = 2, + IA_GOFO_FW_BOOT_UNTRUSTED_ADDR_MIN_ID = 3, + IA_GOFO_FW_BOOT_RESERVED0_ID = IA_GOFO_FW_BOOT_UNTRUSTED_ADDR_MIN_ID, + IA_GOFO_FW_BOOT_MESSAGING_VERSION_ID = 4, + IA_GOFO_FW_BOOT_ID_MAX +}; + +enum ia_gofo_boot_uc_tile_frequency_units { + IA_GOFO_FW_BOOT_UC_FREQUENCY_UNITS_MHZ = 0, + IA_GOFO_FW_BOOT_UC_FREQUENCY_UNITS_HZ = 1, + IA_GOFO_FW_BOOT_UC_FREQUENCY_UNITS_N +}; + +#define IA_GOFO_FW_BOOT_STATE_IS_CRITICAL(boot_state) \ + (0xdead0000U == ((boot_state) & 0xffff0000U)) + +struct ia_gofo_boot_config { + u32 length; + struct ia_gofo_version_s config_version; + struct ia_gofo_msg_version_list client_version_support; + ia_gofo_addr_t pkg_dir; + ia_gofo_addr_t subsys_config; + u32 uc_tile_frequency; + u16 checksum; + u8 uc_tile_frequency_units; + u8 padding[1]; + u32 reserved[IA_GOFO_BOOT_RESERVED_SIZE]; + struct syscom_config_s syscom_context_config; +}; + +struct ia_gofo_secondary_boot_config { + u32 length; + struct ia_gofo_version_s config_version; + struct ia_gofo_msg_version_list client_version_support; + u8 reserved1[IA_GOFO_BOOT_SECONDARY_RESERVED_FIELDS]; + u16 checksum; + u8 padding[2]; + u32 reserved2[IA_GOFO_BOOT_SECONDARY_RESERVED_SIZE]; + struct syscom_config_s syscom_context_config; +}; + +#pragma pack(pop) + +#define IA_GOFO_WDT_TIMEOUT_ERR 0xdead0401U +#define IA_GOFO_MEM_FATAL_DME_ERR 0xdead0801U +#define IA_GOFO_MEM_UNCORRECTABLE_LOCAL_ERR 0xdead0802U +#define IA_GOFO_MEM_UNCORRECTABLE_DIRTY_ERR 0xdead0803U +#define IA_GOFO_MEM_UNCORRECTABLE_DTAG_ERR 0xdead0804U +#define IA_GOFO_MEM_UNCORRECTABLE_CACHE_ERR 0xdead0805U +#define IA_GOFO_DOUBLE_EXCEPTION_ERR 0xdead0806U +#define IA_GOFO_BIST_DMEM_FAULT_DETECTION_ERR 0xdead1000U +#define IA_GOFO_BIST_DATA_INTEGRITY_FAILURE 0xdead1010U + +enum ia_gofo_boot_state { + IA_GOFO_FW_BOOT_STATE_SECONDARY_BOOT_CONFIG_READY = 0x57a7b000U, + IA_GOFO_FW_BOOT_STATE_UNINIT = 0x57a7e000U, + IA_GOFO_FW_BOOT_STATE_STARTING_0 = 0x57a7d000U, + IA_GOFO_FW_BOOT_STATE_CACHE_INIT_DONE = 0x57a7d010U, + IA_GOFO_FW_BOOT_STATE_MEM_INIT_DONE = 0x57a7d020U, + IA_GOFO_FW_BOOT_STATE_STACK_INIT_DONE = 0x57a7d030U, + IA_GOFO_FW_BOOT_STATE_EARLY_BOOT_DONE = 0x57a7d100U, + IA_GOFO_FW_BOOT_STATE_BOOT_CONFIG_START = 0x57a7d200U, + IA_GOFO_FW_BOOT_STATE_QUEUE_INIT_DONE = 0x57a7d300U, + IA_GOFO_FW_BOOT_STATE_READY = 0x57a7e100U, + IA_GOFO_FW_BOOT_STATE_CRIT_UNSPECIFIED = 0xdead0001U, + IA_GOFO_FW_BOOT_STATE_CRIT_CFG_PTR = 0xdead0101U, + IA_GOFO_FW_BOOT_STATE_CRIT_CFG_VERSION = 0xdead0201U, + IA_GOFO_FW_BOOT_STATE_CRIT_MSG_VERSION = 0xdead0301U, + IA_GOFO_FW_BOOT_STATE_CRIT_WDT_TIMEOUT = IA_GOFO_WDT_TIMEOUT_ERR, + IA_GOFO_FW_BOOT_STATE_WRONG_DATA_SECTION_UNPACKING = 0xdead0501U, + IA_GOFO_FW_BOOT_STATE_WRONG_RO_DATA_SECTION_UNPACKING = 0xdead0601U, + IA_GOFO_FW_BOOT_STATE_INVALID_UNTRUSTED_ADDR_MIN = 0xdead0701U, + IA_GOFO_FW_BOOT_STATE_CRIT_MEM_FATAL_DME = IA_GOFO_MEM_FATAL_DME_ERR, + IA_GOFO_FW_BOOT_STATE_CRIT_MEM_UNCORRECTABLE_LOCAL = + IA_GOFO_MEM_UNCORRECTABLE_LOCAL_ERR, + IA_GOFO_FW_BOOT_STATE_CRIT_MEM_UNCORRECTABLE_DIRTY = + IA_GOFO_MEM_UNCORRECTABLE_DIRTY_ERR, + IA_GOFO_FW_BOOT_STATE_CRIT_MEM_UNCORRECTABLE_DTAG = + IA_GOFO_MEM_UNCORRECTABLE_DTAG_ERR, + IA_GOFO_FW_BOOT_STATE_CRIT_MEM_UNCORRECTABLE_CACHE = + IA_GOFO_MEM_UNCORRECTABLE_CACHE_ERR, + IA_GOFO_FW_BOOT_STATE_CRIT_DOUBLE_EXCEPTION = + IA_GOFO_DOUBLE_EXCEPTION_ERR, + IA_GOFO_FW_BOOT_STATE_CRIT_BIST_DMEM_FAULT_DETECTION_ERR = + IA_GOFO_BIST_DMEM_FAULT_DETECTION_ERR, + IA_GOFO_FW_BOOT_STATE_CRIT_DATA_INTEGRITY_FAILURE = 0xdead1010U, + IA_GOFO_FW_BOOT_STATE_CRIT_STACK_CHK_FAILURE = 0xdead1011U, + IA_GOFO_FW_BOOT_STATE_CRIT_SYSCOM_CONTEXT_INTEGRITY_FAILURE = + 0xdead1012U, + IA_GOFO_FW_BOOT_STATE_CRIT_MPU_CONFIG_FAILURE = 0xdead1013U, + IA_GOFO_FW_BOOT_STATE_CRIT_SHARED_BUFFER_FAILURE = 0xdead1014U, + IA_GOFO_FW_BOOT_STATE_CRIT_CMEM_FAILURE = 0xdead1015U, + IA_GOFO_FW_BOOT_STATE_SHUTDOWN_CMD = 0x57a7f001U, + IA_GOFO_FW_BOOT_STATE_SHUTDOWN_START = 0x57a7e200U, + IA_GOFO_FW_BOOT_STATE_INACTIVE = 0x57a7e300U, + IA_GOFO_FW_BOOT_HW_CMD_ACK_TIMEOUT = 0x57a7e400U, + IA_GOFO_FW_BOOT_SYSTEM_CYCLES_ERROR = 0x57a7e500U +}; + +#endif diff --git a/drivers/staging/media/ipu7/abi/ipu7_fw_common_abi.h b/drivers/staging/media/ipu7/abi/ipu7_fw_common_abi.h new file mode 100644 index 0000000000000..7bb6fac585a32 --- /dev/null +++ b/drivers/staging/media/ipu7/abi/ipu7_fw_common_abi.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 - 2025 Intel Corporation + */ + +#ifndef IPU7_FW_COMMOM_ABI_H +#define IPU7_FW_COMMOM_ABI_H + +#include <linux/types.h> + +#pragma pack(push, 1) +typedef u32 ia_gofo_addr_t; + +#define IA_GOFO_ADDR_NULL (0U) + +struct ia_gofo_version_s { + u8 patch; + u8 subminor; + u8 minor; + u8 major; +}; + +#define IA_GOFO_MSG_VERSION_INIT(major_val, minor_val, subminor_val, patch_val)\ + {.major = (major_val), .minor = (minor_val), .subminor = \ + (subminor_val), .patch = (patch_val)} + +#define IA_GOFO_MSG_VERSION_LIST_MAX_ENTRIES (3U) +#define IA_GOFO_MSG_RESERVED_SIZE (3U) + +struct ia_gofo_msg_version_list { + u8 num_versions; + u8 reserved[IA_GOFO_MSG_RESERVED_SIZE]; + struct ia_gofo_version_s versions[IA_GOFO_MSG_VERSION_LIST_MAX_ENTRIES]; +}; + +#pragma pack(pop) + +#define TLV_TYPE_PADDING (0U) + +#pragma pack(push, 1) + +#define IA_GOFO_ABI_BITS_PER_BYTE (8U) + +struct ia_gofo_tlv_header { + u16 tlv_type; + u16 tlv_len32; +}; + +struct ia_gofo_tlv_list { + u16 num_elems; + u16 head_offset; +}; + +#define TLV_ITEM_ALIGNMENT ((u32)sizeof(u32)) +#define TLV_MSG_ALIGNMENT ((u32)sizeof(u64)) +#define TLV_LIST_ALIGNMENT TLV_ITEM_ALIGNMENT +#pragma pack(pop) + +#define IA_GOFO_MODULO(dividend, divisor) ((dividend) % (divisor)) + +#define IA_GOFO_MSG_ERR_MAX_DETAILS (4U) +#define IA_GOFO_MSG_ERR_OK (0U) +#define IA_GOFO_MSG_ERR_UNSPECIFED (0xffffffffU) +#define IA_GOFO_MSG_ERR_GROUP_UNSPECIFIED (0U) +#define IA_GOFO_MSG_ERR_IS_OK(err) (IA_GOFO_MSG_ERR_OK == (err).err_code) + +#pragma pack(push, 1) +struct ia_gofo_msg_err { + u32 err_group; + u32 err_code; + u32 err_detail[IA_GOFO_MSG_ERR_MAX_DETAILS]; +}; + +#pragma pack(pop) + +#define IA_GOFO_MSG_ERR_GROUP_APP_EXT_START (16U) +#define IA_GOFO_MSG_ERR_GROUP_MAX (31U) +#define IA_GOFO_MSG_ERR_GROUP_INTERNAL_START (IA_GOFO_MSG_ERR_GROUP_MAX + 1U) +#define IA_GOFO_MSG_ERR_GROUP_RESERVED IA_GOFO_MSG_ERR_GROUP_UNSPECIFIED +#define IA_GOFO_MSG_ERR_GROUP_GENERAL 1 + +enum ia_gofo_msg_err_general { + IA_GOFO_MSG_ERR_GENERAL_OK = IA_GOFO_MSG_ERR_OK, + IA_GOFO_MSG_ERR_GENERAL_MSG_TOO_SMALL = 1, + IA_GOFO_MSG_ERR_GENERAL_MSG_TOO_LARGE = 2, + IA_GOFO_MSG_ERR_GENERAL_DEVICE_STATE = 3, + IA_GOFO_MSG_ERR_GENERAL_ALIGNMENT = 4, + IA_GOFO_MSG_ERR_GENERAL_INDIRECT_REF_PTR_INVALID = 5, + IA_GOFO_MSG_ERR_GENERAL_INVALID_MSG_TYPE = 6, + IA_GOFO_MSG_ERR_GENERAL_SYSCOM_FAIL = 7, + IA_GOFO_MSG_ERR_GENERAL_N +}; + +#pragma pack(push, 1) +#define IA_GOFO_MSG_TYPE_RESERVED 0 +#define IA_GOFO_MSG_TYPE_INDIRECT 1 +#define IA_GOFO_MSG_TYPE_LOG 2 +#define IA_GOFO_MSG_TYPE_GENERAL_ERR 3 + +struct ia_gofo_msg_header { + struct ia_gofo_tlv_header tlv_header; + struct ia_gofo_tlv_list msg_options; + u64 user_token; +}; + +struct ia_gofo_msg_header_ack { + struct ia_gofo_msg_header header; + struct ia_gofo_msg_err err; + +}; + +struct ia_gofo_msg_general_err { + struct ia_gofo_msg_header_ack header; +}; + +#pragma pack(pop) + +#pragma pack(push, 1) +enum ia_gofo_msg_link_streaming_mode { + IA_GOFO_MSG_LINK_STREAMING_MODE_SOFF = 0, + IA_GOFO_MSG_LINK_STREAMING_MODE_DOFF = 1, + IA_GOFO_MSG_LINK_STREAMING_MODE_BCLM = 2, + IA_GOFO_MSG_LINK_STREAMING_MODE_BCSM_FIX = 3, + IA_GOFO_MSG_LINK_STREAMING_MODE_N +}; + +enum ia_gofo_soc_pbk_instance_id { + IA_GOFO_SOC_PBK_ID0 = 0, + IA_GOFO_SOC_PBK_ID1 = 1, + IA_GOFO_SOC_PBK_ID_N +}; + +#define IA_GOFO_MSG_LINK_PBK_MAX_SLOTS (2U) + +struct ia_gofo_msg_indirect { + struct ia_gofo_msg_header header; + struct ia_gofo_tlv_header ref_header; + ia_gofo_addr_t ref_msg_ptr; +}; + +#pragma pack(pop) + +#pragma pack(push, 1) +#define IA_GOFO_MSG_LOG_MAX_PARAMS (4U) +#define IA_GOFO_MSG_LOG_DOC_FMT_ID_MIN (0U) + +#define IA_GOFO_MSG_LOG_DOC_FMT_ID_MAX (4095U) +#define IA_GOFO_MSG_LOG_FMT_ID_INVALID (0xfffffffU) + +struct ia_gofo_msg_log_info { + u16 log_counter; + u8 msg_parameter_types; + /* [0:0] is_out_of_order, [1:3] logger_channel, [4:7] reserved */ + u8 logger_opts; + u32 fmt_id; + u32 params[IA_GOFO_MSG_LOG_MAX_PARAMS]; +}; + +struct ia_gofo_msg_log_info_ts { + u64 msg_ts; + struct ia_gofo_msg_log_info log_info; +}; + +struct ia_gofo_msg_log { + struct ia_gofo_msg_header header; + struct ia_gofo_msg_log_info_ts log_info_ts; +}; + +#pragma pack(pop) + +#define IA_GOFO_MSG_ABI_OUT_ACK_QUEUE_ID (0U) +#define IA_GOFO_MSG_ABI_OUT_LOG_QUEUE_ID (1U) +#define IA_GOFO_MSG_ABI_IN_DEV_QUEUE_ID (2U) + +#endif diff --git a/drivers/staging/media/ipu7/abi/ipu7_fw_config_abi.h b/drivers/staging/media/ipu7/abi/ipu7_fw_config_abi.h new file mode 100644 index 0000000000000..c3f62aaedd86b --- /dev/null +++ b/drivers/staging/media/ipu7/abi/ipu7_fw_config_abi.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021 - 2025 Intel Corporation + */ + +#ifndef IPU7_FW_CONFIG_ABI_H +#define IPU7_FW_CONFIG_ABI_H + +#include <linux/types.h> + +#define IPU_CONFIG_ABI_WDT_TIMER_DISABLED 0U +#define IPU_CONFIG_ABI_CMD_TIMER_DISABLED 0U + +struct ipu7_wdt_abi { + u32 wdt_timer1_us; + u32 wdt_timer2_us; +}; + +#endif diff --git a/drivers/staging/media/ipu7/abi/ipu7_fw_insys_config_abi.h b/drivers/staging/media/ipu7/abi/ipu7_fw_insys_config_abi.h new file mode 100644 index 0000000000000..f161a605c5006 --- /dev/null +++ b/drivers/staging/media/ipu7/abi/ipu7_fw_insys_config_abi.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021 - 2025 Intel Corporation + */ + +#ifndef IPU7_FW_INSYS_CONFIG_ABI_H +#define IPU7_FW_INSYS_CONFIG_ABI_H + +#include "ipu7_fw_boot_abi.h" +#include "ipu7_fw_config_abi.h" +#include "ipu7_fw_isys_abi.h" + +struct ipu7_insys_config { + u32 timeout_val_ms; + struct ia_gofo_logger_config logger_config; + struct ipu7_wdt_abi wdt_config; +}; + +#endif diff --git a/drivers/staging/media/ipu7/abi/ipu7_fw_isys_abi.h b/drivers/staging/media/ipu7/abi/ipu7_fw_isys_abi.h new file mode 100644 index 0000000000000..c42d0b7a26275 --- /dev/null +++ b/drivers/staging/media/ipu7/abi/ipu7_fw_isys_abi.h @@ -0,0 +1,412 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 - 2025 Intel Corporation + */ + +#ifndef IPU7_FW_ISYS_ABI_H +#define IPU7_FW_ISYS_ABI_H + +#include "ipu7_fw_common_abi.h" +#include "ipu7_fw_isys_abi.h" + +#define IPU_INSYS_MAX_OUTPUT_QUEUES (3U) +#define IPU_INSYS_STREAM_ID_MAX (16U) + +#define IPU_INSYS_MAX_INPUT_QUEUES (IPU_INSYS_STREAM_ID_MAX + 1U) +#define IPU_INSYS_OUTPUT_FIRST_QUEUE (0U) +#define IPU_INSYS_OUTPUT_LAST_QUEUE (IPU_INSYS_MAX_OUTPUT_QUEUES - 1U) +#define IPU_INSYS_OUTPUT_MSG_QUEUE (IPU_INSYS_OUTPUT_FIRST_QUEUE) +#define IPU_INSYS_OUTPUT_LOG_QUEUE (IPU_INSYS_OUTPUT_FIRST_QUEUE + 1U) +#define IPU_INSYS_OUTPUT_RESERVED_QUEUE (IPU_INSYS_OUTPUT_LAST_QUEUE) +#define IPU_INSYS_INPUT_FIRST_QUEUE (IPU_INSYS_MAX_OUTPUT_QUEUES) +#define IPU_INSYS_INPUT_LAST_QUEUE \ + (IPU_INSYS_INPUT_FIRST_QUEUE + IPU_INSYS_MAX_INPUT_QUEUES - 1U) +#define IPU_INSYS_INPUT_DEV_QUEUE (IPU_INSYS_INPUT_FIRST_QUEUE) +#define IPU_INSYS_INPUT_MSG_QUEUE (IPU_INSYS_INPUT_FIRST_QUEUE + 1U) +#define IPU_INSYS_INPUT_MSG_MAX_QUEUE (IPU_INSYS_MAX_INPUT_QUEUES - 1U) + +#define MAX_OPINS_FOR_SINGLE_IPINS (3U) +#define DEV_SEND_QUEUE_SIZE (IPU_INSYS_STREAM_ID_MAX) + +#define PIN_PLANES_MAX (4U) + +#define INSYS_MSG_ERR_STREAM_INSUFFICIENT_RESOURCES_INPUT \ + INSYS_MSG_ERR_STREAM_INSUFFICIENT_RESOURCES + +typedef u64 ipu7_insys_return_token; + +enum ipu7_insys_resp_type { + IPU_INSYS_RESP_TYPE_STREAM_OPEN_DONE = 0, + IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK = 1, + IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK = 2, + IPU_INSYS_RESP_TYPE_STREAM_ABORT_ACK = 3, + IPU_INSYS_RESP_TYPE_STREAM_FLUSH_ACK = 4, + IPU_INSYS_RESP_TYPE_STREAM_CLOSE_ACK = 5, + IPU_INSYS_RESP_TYPE_PIN_DATA_READY = 6, + IPU_INSYS_RESP_TYPE_FRAME_SOF = 7, + IPU_INSYS_RESP_TYPE_FRAME_EOF = 8, + IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE = 9, + IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE = 10, + IPU_INSYS_RESP_TYPE_PWM_IRQ = 11, + N_IPU_INSYS_RESP_TYPE +}; + +enum ipu7_insys_send_type { + IPU_INSYS_SEND_TYPE_STREAM_OPEN = 0, + IPU_INSYS_SEND_TYPE_STREAM_START_AND_CAPTURE = 1, + IPU_INSYS_SEND_TYPE_STREAM_CAPTURE = 2, + IPU_INSYS_SEND_TYPE_STREAM_ABORT = 3, + IPU_INSYS_SEND_TYPE_STREAM_FLUSH = 4, + IPU_INSYS_SEND_TYPE_STREAM_CLOSE = 5, + N_IPU_INSYS_SEND_TYPE +}; + +enum ipu7_insys_mipi_vc { + IPU_INSYS_MIPI_VC_0 = 0, + IPU_INSYS_MIPI_VC_1 = 1, + IPU_INSYS_MIPI_VC_2 = 2, + IPU_INSYS_MIPI_VC_3 = 3, + IPU_INSYS_MIPI_VC_4 = 4, + IPU_INSYS_MIPI_VC_5 = 5, + IPU_INSYS_MIPI_VC_6 = 6, + IPU_INSYS_MIPI_VC_7 = 7, + IPU_INSYS_MIPI_VC_8 = 8, + IPU_INSYS_MIPI_VC_9 = 9, + IPU_INSYS_MIPI_VC_10 = 10, + IPU_INSYS_MIPI_VC_11 = 11, + IPU_INSYS_MIPI_VC_12 = 12, + IPU_INSYS_MIPI_VC_13 = 13, + IPU_INSYS_MIPI_VC_14 = 14, + IPU_INSYS_MIPI_VC_15 = 15, + N_IPU_INSYS_MIPI_VC +}; + +enum ipu7_insys_mipi_port { + IPU_INSYS_MIPI_PORT_0 = 0, + IPU_INSYS_MIPI_PORT_1 = 1, + IPU_INSYS_MIPI_PORT_2 = 2, + IPU_INSYS_MIPI_PORT_3 = 3, + IPU_INSYS_MIPI_PORT_4 = 4, + IPU_INSYS_MIPI_PORT_5 = 5, + NA_IPU_INSYS_MIPI_PORT +}; + +enum ipu7_insys_frame_format_type { + IPU_INSYS_FRAME_FORMAT_NV11 = 0, + IPU_INSYS_FRAME_FORMAT_NV12 = 1, + IPU_INSYS_FRAME_FORMAT_NV12_16 = 2, + IPU_INSYS_FRAME_FORMAT_NV12_TILEY = 3, + IPU_INSYS_FRAME_FORMAT_NV16 = 4, + IPU_INSYS_FRAME_FORMAT_NV21 = 5, + IPU_INSYS_FRAME_FORMAT_NV61 = 6, + IPU_INSYS_FRAME_FORMAT_YV12 = 7, + IPU_INSYS_FRAME_FORMAT_YV16 = 8, + IPU_INSYS_FRAME_FORMAT_YUV420 = 9, + IPU_INSYS_FRAME_FORMAT_YUV420_10 = 10, + IPU_INSYS_FRAME_FORMAT_YUV420_12 = 11, + IPU_INSYS_FRAME_FORMAT_YUV420_14 = 12, + IPU_INSYS_FRAME_FORMAT_YUV420_16 = 13, + IPU_INSYS_FRAME_FORMAT_YUV422 = 14, + IPU_INSYS_FRAME_FORMAT_YUV422_16 = 15, + IPU_INSYS_FRAME_FORMAT_UYVY = 16, + IPU_INSYS_FRAME_FORMAT_YUYV = 17, + IPU_INSYS_FRAME_FORMAT_YUV444 = 18, + IPU_INSYS_FRAME_FORMAT_YUV_LINE = 19, + IPU_INSYS_FRAME_FORMAT_RAW8 = 20, + IPU_INSYS_FRAME_FORMAT_RAW10 = 21, + IPU_INSYS_FRAME_FORMAT_RAW12 = 22, + IPU_INSYS_FRAME_FORMAT_RAW14 = 23, + IPU_INSYS_FRAME_FORMAT_RAW16 = 24, + IPU_INSYS_FRAME_FORMAT_RGB565 = 25, + IPU_INSYS_FRAME_FORMAT_PLANAR_RGB888 = 26, + IPU_INSYS_FRAME_FORMAT_RGBA888 = 27, + IPU_INSYS_FRAME_FORMAT_QPLANE6 = 28, + IPU_INSYS_FRAME_FORMAT_BINARY_8 = 29, + IPU_INSYS_FRAME_FORMAT_Y_8 = 30, + IPU_INSYS_FRAME_FORMAT_ARGB888 = 31, + IPU_INSYS_FRAME_FORMAT_BGRA888 = 32, + IPU_INSYS_FRAME_FORMAT_ABGR888 = 33, + N_IPU_INSYS_FRAME_FORMAT +}; + +#define IPU_INSYS_FRAME_FORMAT_RAW (IPU_INSYS_FRAME_FORMAT_RAW16) +#define N_IPU_INSYS_MIPI_DATA_TYPE 0x40 + +enum ipu7_insys_mipi_dt_rename_mode { + IPU_INSYS_MIPI_DT_NO_RENAME = 0, + IPU_INSYS_MIPI_DT_RENAMED_MODE = 1, + N_IPU_INSYS_MIPI_DT_MODE +}; + +#define IPU_INSYS_SEND_MSG_ENABLED 1U +#define IPU_INSYS_SEND_MSG_DISABLED 0U + +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF BIT(0) +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF BIT(1) +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF BIT(2) +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF BIT(3) +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED BIT(4) +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF_DISCARDED BIT(5) +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED BIT(6) +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF_DISCARDED BIT(7) +#define IPU_INSYS_STREAM_SYNC_MSG_ENABLE_MSG_SEND_RESP ( \ + IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF | \ + IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF | \ + IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED | \ + IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF_DISCARDED) +#define IPU_INSYS_STREAM_SYNC_MSG_ENABLE_MSG_SEND_IRQ ( \ + IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF | \ + IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF | \ + IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED | \ + IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF_DISCARDED) + +#define IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_OPEN_DONE BIT(0) +#define IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_OPEN_DONE BIT(1) +#define IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_START_ACK BIT(2) +#define IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_START_ACK BIT(3) +#define IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_CLOSE_ACK BIT(4) +#define IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_CLOSE_ACK BIT(5) +#define IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_FLUSH_ACK BIT(6) +#define IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_FLUSH_ACK BIT(7) +#define IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_ABORT_ACK BIT(8) +#define IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_ABORT_ACK BIT(9) +#define IPU_INSYS_STREAM_ENABLE_MSG_SEND_RESP ( \ + IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_OPEN_DONE | \ + IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_START_ACK | \ + IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_CLOSE_ACK | \ + IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_FLUSH_ACK | \ + IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_ABORT_ACK) +#define IPU_INSYS_STREAM_ENABLE_MSG_SEND_IRQ ( \ + IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_OPEN_DONE | \ + IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_START_ACK | \ + IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_CLOSE_ACK | \ + IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_FLUSH_ACK | \ + IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_ABORT_ACK) + +#define IPU_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_ACK BIT(0) +#define IPU_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_ACK BIT(1) +#define IPU_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_DONE BIT(2) +#define IPU_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_DONE BIT(3) +#define IPU_INSYS_FRAME_MSG_SEND_RESP_PIN_DATA_READY BIT(4) +#define IPU_INSYS_FRAME_MSG_SEND_IRQ_PIN_DATA_READY BIT(5) +#define IPU_INSYS_FRAME_ENABLE_MSG_SEND_RESP ( \ + IPU_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_ACK | \ + IPU_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_DONE | \ + IPU_INSYS_FRAME_MSG_SEND_RESP_PIN_DATA_READY) +#define IPU_INSYS_FRAME_ENABLE_MSG_SEND_IRQ ( \ + IPU_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_ACK | \ + IPU_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_DONE | \ + IPU_INSYS_FRAME_MSG_SEND_IRQ_PIN_DATA_READY) + +enum ipu7_insys_output_link_dest { + IPU_INSYS_OUTPUT_LINK_DEST_MEM = 0, + IPU_INSYS_OUTPUT_LINK_DEST_PSYS = 1, + IPU_INSYS_OUTPUT_LINK_DEST_IPU_EXTERNAL = 2 +}; + +enum ipu7_insys_dpcm_type { + IPU_INSYS_DPCM_TYPE_DISABLED = 0, + IPU_INSYS_DPCM_TYPE_10_8_10 = 1, + IPU_INSYS_DPCM_TYPE_12_8_12 = 2, + IPU_INSYS_DPCM_TYPE_12_10_12 = 3, + N_IPU_INSYS_DPCM_TYPE +}; + +enum ipu7_insys_dpcm_predictor { + IPU_INSYS_DPCM_PREDICTOR_1 = 0, + IPU_INSYS_DPCM_PREDICTOR_2 = 1, + N_IPU_INSYS_DPCM_PREDICTOR +}; + +enum ipu7_insys_send_queue_token_flag { + IPU_INSYS_SEND_QUEUE_TOKEN_FLAG_NONE = 0, + IPU_INSYS_SEND_QUEUE_TOKEN_FLAG_FLUSH_FORCE = 1 +}; + +#pragma pack(push, 1) +struct ipu7_insys_resolution { + u32 width; + u32 height; +}; + +struct ipu7_insys_capture_output_pin_payload { + u64 user_token; + ia_gofo_addr_t addr; + u8 pad[4]; +}; + +struct ipu7_insys_output_link { + u32 buffer_lines; + u16 foreign_key; + u16 granularity_pointer_update; + u8 msg_link_streaming_mode; + u8 pbk_id; + u8 pbk_slot_id; + u8 dest; + u8 use_sw_managed; + u8 is_snoop; + u8 pad[2]; +}; + +struct ipu7_insys_output_cropping { + u16 line_top; + u16 line_bottom; +}; + +struct ipu7_insys_output_dpcm { + u8 enable; + u8 type; + u8 predictor; + u8 pad; +}; + +struct ipu7_insys_output_pin { + struct ipu7_insys_output_link link; + struct ipu7_insys_output_cropping crop; + struct ipu7_insys_output_dpcm dpcm; + u32 stride; + u16 ft; + u8 send_irq; + u8 input_pin_id; + u8 early_ack_en; + u8 pad[3]; +}; + +struct ipu7_insys_input_pin { + struct ipu7_insys_resolution input_res; + u16 sync_msg_map; + u8 dt; + u8 disable_mipi_unpacking; + u8 dt_rename_mode; + u8 mapped_dt; + u8 pad[2]; +}; + +struct ipu7_insys_stream_cfg { + struct ipu7_insys_input_pin input_pins[4]; + struct ipu7_insys_output_pin output_pins[4]; + u16 stream_msg_map; + u8 port_id; + u8 vc; + u8 nof_input_pins; + u8 nof_output_pins; + u8 pad[2]; +}; + +struct ipu7_insys_buffset { + struct ipu7_insys_capture_output_pin_payload output_pins[4]; + u8 capture_msg_map; + u8 frame_id; + u8 skip_frame; + u8 pad[5]; +}; + +struct ipu7_insys_resp { + u64 buf_id; + struct ipu7_insys_capture_output_pin_payload pin; + struct ia_gofo_msg_err error_info; + u32 timestamp[2]; + u8 type; + u8 msg_link_streaming_mode; + u8 stream_id; + u8 pin_id; + u8 frame_id; + u8 skip_frame; + u8 pad[2]; +}; + +struct ipu7_insys_resp_queue_token { + struct ipu7_insys_resp resp_info; +}; + +struct ipu7_insys_send_queue_token { + u64 buf_handle; + ia_gofo_addr_t addr; + u16 stream_id; + u8 send_type; + u8 flag; +}; + +#pragma pack(pop) + +enum insys_msg_err_stream { + INSYS_MSG_ERR_STREAM_OK = IA_GOFO_MSG_ERR_OK, + INSYS_MSG_ERR_STREAM_STREAM_ID = 1, + INSYS_MSG_ERR_STREAM_MAX_OPINS = 2, + INSYS_MSG_ERR_STREAM_MAX_IPINS = 3, + INSYS_MSG_ERR_STREAM_STREAM_MESSAGES_MAP = 4, + INSYS_MSG_ERR_STREAM_SYNC_MESSAGES_MAP = 5, + INSYS_MSG_ERR_STREAM_SENSOR_TYPE = 6, + INSYS_MSG_ERR_STREAM_FOREIGN_KEY = 7, + INSYS_MSG_ERR_STREAM_STREAMING_MODE = 8, + INSYS_MSG_ERR_STREAM_DPCM_EN = 9, + INSYS_MSG_ERR_STREAM_DPCM_TYPE = 10, + INSYS_MSG_ERR_STREAM_DPCM_PREDICTOR = 11, + INSYS_MSG_ERR_STREAM_GRANULARITY_POINTER_UPDATE = 12, + INSYS_MSG_ERR_STREAM_MPF_LUT_ENTRY_RESOURCES_BUSY = 13, + INSYS_MSG_ERR_STREAM_MPF_DEV_ID = 14, + INSYS_MSG_ERR_STREAM_BUFFER_LINES = 15, + INSYS_MSG_ERR_STREAM_IPIN_ID = 16, + INSYS_MSG_ERR_STREAM_DATA_TYPE = 17, + INSYS_MSG_ERR_STREAM_STREAMING_PROTOCOL_STATE = 18, + INSYS_MSG_ERR_STREAM_SYSCOM_FLUSH = 19, + INSYS_MSG_ERR_STREAM_MIPI_VC = 20, + INSYS_MSG_ERR_STREAM_STREAM_SRC = 21, + INSYS_MSG_ERR_STREAM_PBK_ID = 22, + INSYS_MSG_ERR_STREAM_CMD_QUEUE_DEALLOCATE = 23, + INSYS_MSG_ERR_STREAM_INSUFFICIENT_RESOURCES = 24, + INSYS_MSG_ERR_STREAM_IPIN_CONFIGURATION = 25, + INSYS_MSG_ERR_STREAM_INVALID_STATE = 26, + INSYS_MSG_ERR_STREAM_SW_MANAGED = 27, + INSYS_MSG_ERR_STREAM_PBK_SLOT_ID = 28, + INSYS_MSG_ERR_STREAM_FLUSH_TIMEOUT = 29, + INSYS_MSG_ERR_STREAM_IPIN_WIDTH = 30, + INSYS_MSG_ERR_STREAM_IPIN_HEIGHT = 31, + INSYS_MSG_ERR_STREAM_OUTPUT_PIN_EARLY_ACK_EN = 32, + INSYS_MSG_ERR_STREAM_INCONSISTENT_PARAMS = 33, + INSYS_MSG_ERR_STREAM_PLANE_COUNT = 34, + INSYS_MSG_ERR_STREAM_FRAME_FORMAT_TYPE = 35, + INSYS_MSG_ERR_STREAM_INSUFFICIENT_RESOURCES_OUTPUT = 36, + INSYS_MSG_ERR_STREAM_WIDTH_OUTPUT_SIZE = 37, + INSYS_MSG_ERR_STREAM_CLOSED = 38, + INSYS_MSG_ERR_STREAM_N +}; + +enum insys_msg_err_capture { + INSYS_MSG_ERR_CAPTURE_OK = IA_GOFO_MSG_ERR_OK, + INSYS_MSG_ERR_CAPTURE_STREAM_ID = 1, + INSYS_MSG_ERR_CAPTURE_PAYLOAD_PTR = 2, + INSYS_MSG_ERR_CAPTURE_MEM_SLOT = 3, + INSYS_MSG_ERR_CAPTURE_STREAMING_MODE = 4, + INSYS_MSG_ERR_CAPTURE_AVAILABLE_CMD_SLOT = 5, + INSYS_MSG_ERR_CAPTURE_CONSUMED_CMD_SLOT = 6, + INSYS_MSG_ERR_CAPTURE_CMD_SLOT_PAYLOAD_PTR = 7, + INSYS_MSG_ERR_CAPTURE_CMD_PREPARE = 8, + INSYS_MSG_ERR_CAPTURE_OUTPUT_PIN = 9, + INSYS_MSG_ERR_CAPTURE_SYNC_FRAME_DROP = 10, + INSYS_MSG_ERR_CAPTURE_FRAME_MESSAGES_MAP = 11, + INSYS_MSG_ERR_CAPTURE_TIMEOUT = 12, + INSYS_MSG_ERR_CAPTURE_INVALID_STREAM_STATE = 13, + INSYS_MSG_ERR_CAPTURE_HW_ERR_MULTIBIT_PH_ERROR_DETECTED = 14, + INSYS_MSG_ERR_CAPTURE_HW_ERR_PAYLOAD_CRC_ERROR = 15, + INSYS_MSG_ERR_CAPTURE_HW_ERR_INPUT_DATA_LOSS_ELASTIC_FIFO_OVFL = 16, + INSYS_MSG_ERR_CAPTURE_HW_ERR_PIXEL_BUFFER_OVERFLOW = 17, + INSYS_MSG_ERR_CAPTURE_HW_ERR_BAD_FRAME_DIM = 18, + INSYS_MSG_ERR_CAPTURE_HW_ERR_PHY_SYNC_ERR = 19, + INSYS_MSG_ERR_CAPTURE_HW_ERR_SECURE_TOUCH = 20, + INSYS_MSG_ERR_CAPTURE_HW_ERR_MASTER_SLAVE_SYNC_ERR = 21, + INSYS_MSG_ERR_CAPTURE_FRAME_SKIP_ERR = 22, + INSYS_MSG_ERR_CAPTURE_FE_INPUT_FIFO_OVERFLOW_ERR = 23, + INSYS_MSG_ERR_CAPTURE_CMD_SUBMIT_TO_HW = 24, + INSYS_MSG_ERR_CAPTURE_N +}; + +enum insys_msg_err_groups { + INSYS_MSG_ERR_GROUP_RESERVED = IA_GOFO_MSG_ERR_GROUP_RESERVED, + INSYS_MSG_ERR_GROUP_GENERAL = IA_GOFO_MSG_ERR_GROUP_GENERAL, + INSYS_MSG_ERR_GROUP_STREAM = 2, + INSYS_MSG_ERR_GROUP_CAPTURE = 3, + INSYS_MSG_ERR_GROUP_N, +}; + +#endif diff --git a/drivers/staging/media/ipu7/abi/ipu7_fw_msg_abi.h b/drivers/staging/media/ipu7/abi/ipu7_fw_msg_abi.h new file mode 100644 index 0000000000000..8a78dd0936df3 --- /dev/null +++ b/drivers/staging/media/ipu7/abi/ipu7_fw_msg_abi.h @@ -0,0 +1,465 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 - 2025 Intel Corporation + */ + +#ifndef IPU7_FW_MSG_ABI_H +#define IPU7_FW_MSG_ABI_H + +#include "ipu7_fw_common_abi.h" + +#pragma pack(push, 1) +enum ipu7_msg_type { + IPU_MSG_TYPE_RESERVED = IA_GOFO_MSG_TYPE_RESERVED, + IPU_MSG_TYPE_INDIRECT = IA_GOFO_MSG_TYPE_INDIRECT, + IPU_MSG_TYPE_DEV_LOG = IA_GOFO_MSG_TYPE_LOG, + IPU_MSG_TYPE_GENERAL_ERR = IA_GOFO_MSG_TYPE_GENERAL_ERR, + IPU_MSG_TYPE_DEV_OPEN = 4, + IPU_MSG_TYPE_DEV_OPEN_ACK = 5, + IPU_MSG_TYPE_GRAPH_OPEN = 6, + IPU_MSG_TYPE_GRAPH_OPEN_ACK = 7, + IPU_MSG_TYPE_TASK_REQ = 8, + IPU_MSG_TYPE_TASK_DONE = 9, + IPU_MSG_TYPE_GRAPH_CLOSE = 10, + IPU_MSG_TYPE_GRAPH_CLOSE_ACK = 11, + IPU_MSG_TYPE_DEV_CLOSE = 12, + IPU_MSG_TYPE_DEV_CLOSE_ACK = 13, + IPU_MSG_TYPE_TERM_EVENT = 14, + IPU_MSG_TYPE_N, +}; + +#define IPU_MSG_MAX_NODE_TERMS (64U) +#define IPU_MSG_MAX_FRAGS (7U) + +enum ipu7_msg_node_type { + IPU_MSG_NODE_TYPE_PAD = 0, + IPU_MSG_NODE_TYPE_BASE, + IPU_MSG_NODE_TYPE_N +}; + +#define IPU_MSG_NODE_MAX_DEVICES (128U) +#define DEB_NUM_UINT32 (IPU_MSG_NODE_MAX_DEVICES / (sizeof(u32) * 8U)) + +typedef u32 ipu7_msg_teb_t[2]; +typedef u32 ipu7_msg_deb_t[DEB_NUM_UINT32]; + +#define IPU_MSG_NODE_MAX_ROUTE_ENABLES (128U) +#define RBM_NUM_UINT32 (IPU_MSG_NODE_MAX_ROUTE_ENABLES / (sizeof(u32) * 8U)) + +typedef u32 ipu7_msg_rbm_t[RBM_NUM_UINT32]; + +enum ipu7_msg_node_profile_type { + IPU_MSG_NODE_PROFILE_TYPE_PAD = 0, + IPU_MSG_NODE_PROFILE_TYPE_BASE, + IPU_MSG_NODE_PROFILE_TYPE_CB, + IPU_MSG_NODE_PROFILE_TYPE_N +}; + +struct ipu7_msg_node_profile { + struct ia_gofo_tlv_header tlv_header; + ipu7_msg_teb_t teb; +}; + +struct ipu7_msg_cb_profile { + struct ipu7_msg_node_profile profile_base; + ipu7_msg_deb_t deb; + ipu7_msg_rbm_t rbm; + ipu7_msg_rbm_t reb; +}; + +#define IPU_MSG_NODE_MAX_PROFILES (2U) +#define IPU_MSG_NODE_DEF_PROFILE_IDX (0U) +#define IPU_MSG_NODE_RSRC_ID_EXT_IP (0xffU) + +#define IPU_MSG_NODE_DONT_CARE_TEB_HI (0xffffffffU) +#define IPU_MSG_NODE_DONT_CARE_TEB_LO (0xffffffffU) +#define IPU_MSG_NODE_RSRC_ID_IS (0xfeU) + +struct ipu7_msg_node { + struct ia_gofo_tlv_header tlv_header; + u8 node_rsrc_id; + u8 node_ctx_id; + u8 num_frags; + u8 reserved[1]; + struct ia_gofo_tlv_list profiles_list; + struct ia_gofo_tlv_list terms_list; + struct ia_gofo_tlv_list node_options; +}; + +enum ipu7_msg_node_option_types { + IPU_MSG_NODE_OPTION_TYPES_PADDING = 0, + IPU_MSG_NODE_OPTION_TYPES_N +}; + +#pragma pack(pop) + +#pragma pack(push, 1) + +enum ipu7_msg_link_type { + IPU_MSG_LINK_TYPE_PAD = 0, + IPU_MSG_LINK_TYPE_GENERIC = 1, + IPU_MSG_LINK_TYPE_N +}; + +enum ipu7_msg_link_option_types { + IPU_MSG_LINK_OPTION_TYPES_PADDING = 0, + IPU_MSG_LINK_OPTION_TYPES_CMPRS = 1, + IPU_MSG_LINK_OPTION_TYPES_N +}; + +enum ipu7_msg_link_cmprs_option_bit_depth { + IPU_MSG_LINK_CMPRS_OPTION_8BPP = 0, + IPU_MSG_LINK_CMPRS_OPTION_10BPP = 1, + IPU_MSG_LINK_CMPRS_OPTION_12BPP = 2, +}; + +#define IPU_MSG_LINK_CMPRS_SPACE_SAVING_DENOM (128U) +#define IPU_MSG_LINK_CMPRS_LOSSY_CFG_PAYLOAD_SIZE (5U) +#define IPU_MSG_LINK_CMPRS_SPACE_SAVING_NUM_MAX \ + (IPU_MSG_LINK_CMPRS_SPACE_SAVING_DENOM - 1U) + +struct ipu7_msg_link_cmprs_plane_desc { + u8 plane_enable; + u8 cmprs_enable; + u8 encoder_plane_id; + u8 decoder_plane_id; + u8 cmprs_is_lossy; + u8 cmprs_is_footprint; + u8 bit_depth; + u8 space_saving_numerator; + u32 pixels_offset; + u32 ts_offset; + u32 tile_row_to_tile_row_stride; + u32 rows_of_tiles; + u32 lossy_cfg[IPU_MSG_LINK_CMPRS_LOSSY_CFG_PAYLOAD_SIZE]; +}; + +#define IPU_MSG_LINK_CMPRS_MAX_PLANES (2U) +#define IPU_MSG_LINK_CMPRS_NO_ALIGN_INTERVAL (0U) +#define IPU_MSG_LINK_CMPRS_MIN_ALIGN_INTERVAL (16U) +#define IPU_MSG_LINK_CMPRS_MAX_ALIGN_INTERVAL (1024U) +struct ipu7_msg_link_cmprs_option { + struct ia_gofo_tlv_header header; + u32 cmprs_buf_size; + u16 align_interval; + u8 reserved[2]; + struct ipu7_msg_link_cmprs_plane_desc plane_descs[2]; +}; + +struct ipu7_msg_link_ep { + u8 node_ctx_id; + u8 term_id; +}; + +struct ipu7_msg_link_ep_pair { + struct ipu7_msg_link_ep ep_src; + struct ipu7_msg_link_ep ep_dst; +}; + +#define IPU_MSG_LINK_FOREIGN_KEY_NONE (65535U) +#define IPU_MSG_LINK_FOREIGN_KEY_MAX (64U) +#define IPU_MSG_LINK_PBK_ID_DONT_CARE (255U) +#define IPU_MSG_LINK_PBK_SLOT_ID_DONT_CARE (255U) +#define IPU_MSG_LINK_TERM_ID_DONT_CARE (0xffU) + +struct ipu7_msg_link { + struct ia_gofo_tlv_header tlv_header; + struct ipu7_msg_link_ep_pair endpoints; + u16 foreign_key; + u8 streaming_mode; + u8 pbk_id; + u8 pbk_slot_id; + u8 delayed_link; + u8 reserved[2]; + struct ia_gofo_tlv_list link_options; +}; + +#pragma pack(pop) + +enum ipu7_msg_dev_state { + IPU_MSG_DEV_STATE_CLOSED = 0, + IPU_MSG_DEV_STATE_OPEN_WAIT = 1, + IPU_MSG_DEV_STATE_OPEN = 2, + IPU_MSG_DEV_STATE_CLOSE_WAIT = 3, + IPU_MSG_DEV_STATE_N +}; + +enum ipu7_msg_graph_state { + IPU_MSG_GRAPH_STATE_CLOSED = 0, + IPU_MSG_GRAPH_STATE_OPEN_WAIT = 1, + IPU_MSG_GRAPH_STATE_OPEN = 2, + IPU_MSG_GRAPH_STATE_CLOSE_WAIT = 3, + IPU_MSG_GRAPH_STATE_N +}; + +enum ipu7_msg_task_state { + IPU_MSG_TASK_STATE_DONE = 0, + IPU_MSG_TASK_STATE_WAIT_DONE = 1, + IPU_MSG_TASK_STATE_N +}; + +enum ipu7_msg_err_groups { + IPU_MSG_ERR_GROUP_RESERVED = IA_GOFO_MSG_ERR_GROUP_RESERVED, + IPU_MSG_ERR_GROUP_GENERAL = IA_GOFO_MSG_ERR_GROUP_GENERAL, + IPU_MSG_ERR_GROUP_DEVICE = 2, + IPU_MSG_ERR_GROUP_GRAPH = 3, + IPU_MSG_ERR_GROUP_TASK = 4, + IPU_MSG_ERR_GROUP_N, +}; + +#pragma pack(push, 1) +struct ipu7_msg_task { + struct ia_gofo_msg_header header; + u8 graph_id; + u8 profile_idx; + u8 node_ctx_id; + u8 frame_id; + u8 frag_id; + u8 req_done_msg; + u8 req_done_irq; + u8 reserved[1]; + ipu7_msg_teb_t payload_reuse_bm; + ia_gofo_addr_t term_buffers[IPU_MSG_MAX_NODE_TERMS]; +}; + +struct ipu7_msg_task_done { + struct ia_gofo_msg_header_ack header; + u8 graph_id; + u8 frame_id; + u8 node_ctx_id; + u8 profile_idx; + u8 frag_id; + u8 reserved[3]; +}; + +enum ipu7_msg_err_task { + IPU_MSG_ERR_TASK_OK = IA_GOFO_MSG_ERR_OK, + IPU_MSG_ERR_TASK_GRAPH_ID = 1, + IPU_MSG_ERR_TASK_NODE_CTX_ID = 2, + IPU_MSG_ERR_TASK_PROFILE_IDX = 3, + IPU_MSG_ERR_TASK_CTX_MEMORY_TASK = 4, + IPU_MSG_ERR_TASK_TERM_PAYLOAD_PTR = 5, + IPU_MSG_ERR_TASK_FRAME_ID = 6, + IPU_MSG_ERR_TASK_FRAG_ID = 7, + IPU_MSG_ERR_TASK_EXEC_EXT = 8, + IPU_MSG_ERR_TASK_EXEC_SBX = 9, + IPU_MSG_ERR_TASK_EXEC_INT = 10, + IPU_MSG_ERR_TASK_EXEC_UNKNOWN = 11, + IPU_MSG_ERR_TASK_PRE_EXEC = 12, + IPU_MSG_ERR_TASK_N +}; + +#pragma pack(pop) + +#pragma pack(push, 1) +enum ipu7_msg_term_type { + IPU_MSG_TERM_TYPE_PAD = 0, + IPU_MSG_TERM_TYPE_BASE, + IPU_MSG_TERM_TYPE_N, +}; + +#define IPU_MSG_TERM_EVENT_TYPE_NONE 0U +#define IPU_MSG_TERM_EVENT_TYPE_PROGRESS 1U +#define IPU_MSG_TERM_EVENT_TYPE_N (IPU_MSG_TERM_EVENT_TYPE_PROGRESS + 1U) + +struct ipu7_msg_term { + struct ia_gofo_tlv_header tlv_header; + u8 term_id; + u8 event_req_bm; + u8 reserved[2]; + u32 payload_size; + struct ia_gofo_tlv_list term_options; +}; + +enum ipu7_msg_term_option_types { + IPU_MSG_TERM_OPTION_TYPES_PADDING = 0, + IPU_MSG_TERM_OPTION_TYPES_N +}; + +struct ipu7_msg_term_event { + struct ia_gofo_msg_header header; + u8 graph_id; + u8 frame_id; + u8 node_ctx_id; + u8 profile_idx; + u8 frag_id; + u8 term_id; + u8 event_type; + u8 reserved[1]; + u64 event_ts; +}; + +#pragma pack(pop) + +#pragma pack(push, 1) +#define IPU_MSG_DEVICE_SEND_MSG_ENABLED 1U +#define IPU_MSG_DEVICE_SEND_MSG_DISABLED 0U + +#define IPU_MSG_DEVICE_OPEN_SEND_RESP BIT(0) +#define IPU_MSG_DEVICE_OPEN_SEND_IRQ BIT(1) + +#define IPU_MSG_DEVICE_CLOSE_SEND_RESP BIT(0) +#define IPU_MSG_DEVICE_CLOSE_SEND_IRQ BIT(1) + +struct ipu7_msg_dev_open { + struct ia_gofo_msg_header header; + u32 max_graphs; + u8 dev_msg_map; + u8 enable_power_gating; + u8 reserved[2]; +}; + +struct ipu7_msg_dev_open_ack { + struct ia_gofo_msg_header_ack header; +}; + +struct ipu7_msg_dev_close { + struct ia_gofo_msg_header header; + u8 dev_msg_map; + u8 reserved[7]; +}; + +struct ipu7_msg_dev_close_ack { + struct ia_gofo_msg_header_ack header; +}; + +enum ipu7_msg_err_device { + IPU_MSG_ERR_DEVICE_OK = IA_GOFO_MSG_ERR_OK, + IPU_MSG_ERR_DEVICE_MAX_GRAPHS = 1, + IPU_MSG_ERR_DEVICE_MSG_MAP = 2, + IPU_MSG_ERR_DEVICE_N +}; + +#pragma pack(pop) + +#pragma pack(push, 1) +#define IPU_MSG_GRAPH_ID_UNKNOWN (0xffU) +#define IPU_MSG_GRAPH_SEND_MSG_ENABLED 1U +#define IPU_MSG_GRAPH_SEND_MSG_DISABLED 0U + +#define IPU_MSG_GRAPH_OPEN_SEND_RESP BIT(0) +#define IPU_MSG_GRAPH_OPEN_SEND_IRQ BIT(1) + +#define IPU_MSG_GRAPH_CLOSE_SEND_RESP BIT(0) +#define IPU_MSG_GRAPH_CLOSE_SEND_IRQ BIT(1) + +struct ipu7_msg_graph_open { + struct ia_gofo_msg_header header; + struct ia_gofo_tlv_list nodes; + struct ia_gofo_tlv_list links; + u8 graph_id; + u8 graph_msg_map; + u8 reserved[6]; +}; + +enum ipu7_msg_graph_ack_option_types { + IPU_MSG_GRAPH_ACK_OPTION_TYPES_PADDING = 0, + IPU_MSG_GRAPH_ACK_TASK_Q_INFO, + IPU_MSG_GRAPH_ACK_OPTION_TYPES_N +}; + +struct ipu7_msg_graph_open_ack_task_q_info { + struct ia_gofo_tlv_header header; + u8 node_ctx_id; + u8 q_id; + u8 reserved[2]; +}; + +struct ipu7_msg_graph_open_ack { + struct ia_gofo_msg_header_ack header; + u8 graph_id; + u8 reserved[7]; +}; + +struct ipu7_msg_graph_close { + struct ia_gofo_msg_header header; + u8 graph_id; + u8 graph_msg_map; + u8 reserved[6]; +}; + +struct ipu7_msg_graph_close_ack { + struct ia_gofo_msg_header_ack header; + u8 graph_id; + u8 reserved[7]; +}; + +enum ipu7_msg_err_graph { + IPU_MSG_ERR_GRAPH_OK = IA_GOFO_MSG_ERR_OK, + IPU_MSG_ERR_GRAPH_GRAPH_STATE = 1, + IPU_MSG_ERR_GRAPH_MAX_GRAPHS = 2, + IPU_MSG_ERR_GRAPH_GRAPH_ID = 3, + IPU_MSG_ERR_GRAPH_NODE_CTX_ID = 4, + IPU_MSG_ERR_GRAPH_NODE_RSRC_ID = 5, + IPU_MSG_ERR_GRAPH_PROFILE_IDX = 6, + IPU_MSG_ERR_GRAPH_TERM_ID = 7, + IPU_MSG_ERR_GRAPH_TERM_PAYLOAD_SIZE = 8, + IPU_MSG_ERR_GRAPH_LINK_NODE_CTX_ID = 9, + IPU_MSG_ERR_GRAPH_LINK_TERM_ID = 10, + IPU_MSG_ERR_GRAPH_PROFILE_TYPE = 11, + IPU_MSG_ERR_GRAPH_NUM_FRAGS = 12, + IPU_MSG_ERR_GRAPH_QUEUE_ID_USAGE = 13, + IPU_MSG_ERR_GRAPH_QUEUE_OPEN = 14, + IPU_MSG_ERR_GRAPH_QUEUE_CLOSE = 15, + IPU_MSG_ERR_GRAPH_QUEUE_ID_TASK_REQ_MISMATCH = 16, + IPU_MSG_ERR_GRAPH_CTX_MEMORY_FGRAPH = 17, + IPU_MSG_ERR_GRAPH_CTX_MEMORY_NODE = 18, + IPU_MSG_ERR_GRAPH_CTX_MEMORY_NODE_PROFILE = 19, + IPU_MSG_ERR_GRAPH_CTX_MEMORY_TERM = 20, + IPU_MSG_ERR_GRAPH_CTX_MEMORY_LINK = 21, + IPU_MSG_ERR_GRAPH_CTX_MSG_MAP = 22, + IPU_MSG_ERR_GRAPH_CTX_FOREIGN_KEY = 23, + IPU_MSG_ERR_GRAPH_CTX_STREAMING_MODE = 24, + IPU_MSG_ERR_GRAPH_CTX_PBK_RSRC = 25, + IPU_MSG_ERR_GRAPH_UNSUPPORTED_EVENT_TYPE = 26, + IPU_MSG_ERR_GRAPH_TOO_MANY_EVENTS = 27, + IPU_MSG_ERR_GRAPH_CTX_MEMORY_CMPRS = 28, + IPU_MSG_ERR_GRAPH_CTX_CMPRS_ALIGN_INTERVAL = 29, + IPU_MSG_ERR_GRAPH_CTX_CMPRS_PLANE_ID = 30, + IPU_MSG_ERR_GRAPH_CTX_CMPRS_UNSUPPORTED_MODE = 31, + IPU_MSG_ERR_GRAPH_CTX_CMPRS_BIT_DEPTH = 32, + IPU_MSG_ERR_GRAPH_CTX_CMPRS_STRIDE_ALIGNMENT = 33, + IPU_MSG_ERR_GRAPH_CTX_CMPRS_SUB_BUFFER_ALIGNMENT = 34, + IPU_MSG_ERR_GRAPH_CTX_CMPRS_LAYOUT_ORDER = 35, + IPU_MSG_ERR_GRAPH_CTX_CMPRS_LAYOUT_OVERLAP = 36, + IPU_MSG_ERR_GRAPH_CTX_CMPRS_BUFFER_TOO_SMALL = 37, + IPU_MSG_ERR_GRAPH_CTX_DELAYED_LINK = 38, + IPU_MSG_ERR_GRAPH_N +}; + +#pragma pack(pop) + +#define FWPS_MSG_ABI_MAX_INPUT_QUEUES (60U) +#define FWPS_MSG_ABI_MAX_OUTPUT_QUEUES (2U) +#define FWPS_MSG_ABI_MAX_QUEUES \ + (FWPS_MSG_ABI_MAX_OUTPUT_QUEUES + FWPS_MSG_ABI_MAX_INPUT_QUEUES) + +#define FWPS_MSG_ABI_OUT_ACK_QUEUE_ID (IA_GOFO_MSG_ABI_OUT_ACK_QUEUE_ID) +#define FWPS_MSG_ABI_OUT_LOG_QUEUE_ID (IA_GOFO_MSG_ABI_OUT_LOG_QUEUE_ID) +#if (FWPS_MSG_ABI_OUT_LOG_QUEUE_ID >= FWPS_MSG_ABI_MAX_OUTPUT_QUEUES) +#error "Maximum output queues configuration is too small to fit ACK and LOG \ +queues" +#endif +#define FWPS_MSG_ABI_IN_DEV_QUEUE_ID (IA_GOFO_MSG_ABI_IN_DEV_QUEUE_ID) +#define FWPS_MSG_ABI_IN_RESERVED_QUEUE_ID (3U) +#define FWPS_MSG_ABI_IN_FIRST_TASK_QUEUE_ID \ + (FWPS_MSG_ABI_IN_RESERVED_QUEUE_ID + 1U) + +#if (FWPS_MSG_ABI_IN_FIRST_TASK_QUEUE_ID >= FWPS_MSG_ABI_MAX_INPUT_QUEUES) +#error "Maximum queues configuration is too small to fit minimum number of \ +useful queues" +#endif + +#define FWPS_MSG_ABI_IN_LAST_TASK_QUEUE_ID (FWPS_MSG_ABI_MAX_QUEUES - 1U) +#define FWPS_MSG_ABI_IN_MAX_TASK_QUEUES \ + (FWPS_MSG_ABI_IN_LAST_TASK_QUEUE_ID - \ + FWPS_MSG_ABI_IN_FIRST_TASK_QUEUE_ID + 1U) +#define FWPS_MSG_ABI_OUT_FIRST_QUEUE_ID (FWPS_MSG_ABI_OUT_ACK_QUEUE_ID) +#define FWPS_MSG_ABI_OUT_LAST_QUEUE_ID (FWPS_MSG_ABI_MAX_OUTPUT_QUEUES - 1U) +#define FWPS_MSG_ABI_IN_FIRST_QUEUE_ID (FWPS_MSG_ABI_IN_DEV_QUEUE_ID) +#define FWPS_MSG_ABI_IN_LAST_QUEUE_ID (FWPS_MSG_ABI_IN_LAST_TASK_QUEUE_ID) + +#define FWPS_MSG_HOST2FW_MAX_SIZE (2U * 1024U) +#define FWPS_MSG_FW2HOST_MAX_SIZE (256U) + +#endif diff --git a/drivers/staging/media/ipu7/abi/ipu7_fw_psys_config_abi.h b/drivers/staging/media/ipu7/abi/ipu7_fw_psys_config_abi.h new file mode 100644 index 0000000000000..0af04c8c6a884 --- /dev/null +++ b/drivers/staging/media/ipu7/abi/ipu7_fw_psys_config_abi.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 - 2025 Intel Corporation + */ + +#ifndef IPU7_PSYS_CONFIG_ABI_H_INCLUDED__ +#define IPU7_PSYS_CONFIG_ABI_H_INCLUDED__ + +#include <linux/types.h> + +#include "ipu7_fw_boot_abi.h" +#include "ipu7_fw_config_abi.h" + +struct ipu7_psys_config { + u32 use_debug_manifest; + u32 timeout_val_ms; + u32 compression_support_enabled; + struct ia_gofo_logger_config logger_config; + struct ipu7_wdt_abi wdt_config; + u8 ipu_psys_debug_bitmask; + u8 padding[3]; +}; + +#endif diff --git a/drivers/staging/media/ipu7/abi/ipu7_fw_syscom_abi.h b/drivers/staging/media/ipu7/abi/ipu7_fw_syscom_abi.h new file mode 100644 index 0000000000000..bfa5258d5b973 --- /dev/null +++ b/drivers/staging/media/ipu7/abi/ipu7_fw_syscom_abi.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 - 2025 Intel Corporation + */ + +#ifndef IPU7_FW_SYSCOM_ABI_H +#define IPU7_FW_SYSCOM_ABI_H + +#include <linux/types.h> + +#include "ipu7_fw_common_abi.h" + +#pragma pack(push, 1) +#define SYSCOM_QUEUE_MIN_CAPACITY 2U + +struct syscom_queue_params_config { + ia_gofo_addr_t token_array_mem; + u16 token_size_in_bytes; + u16 max_capacity; +}; + +struct syscom_config_s { + u16 max_output_queues; + u16 max_input_queues; +}; + +#pragma pack(pop) + +static inline struct syscom_queue_params_config * +syscom_config_get_queue_configs(struct syscom_config_s *config) +{ + return (struct syscom_queue_params_config *)(&config[1]); +} + +static inline const struct syscom_queue_params_config * +syscom_config_get_queue_configs_const(const struct syscom_config_s *config) +{ + return (const struct syscom_queue_params_config *)(&config[1]); +} + +#pragma pack(push, 1) +struct syscom_queue_indices_s { + u32 read_index; + u32 write_index; +}; + +#pragma pack(pop) + +#endif diff --git a/drivers/staging/media/ipu7/ipu7-boot.c b/drivers/staging/media/ipu7/ipu7-boot.c new file mode 100644 index 0000000000000..d7901ff78b38a --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-boot.c @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 - 2025 Intel Corporation + */ + +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/module.h> +#include <linux/iopoll.h> +#include <linux/string.h> +#include <linux/types.h> + +#include "abi/ipu7_fw_boot_abi.h" + +#include "ipu7.h" +#include "ipu7-boot.h" +#include "ipu7-bus.h" +#include "ipu7-buttress-regs.h" +#include "ipu7-dma.h" +#include "ipu7-platform-regs.h" +#include "ipu7-syscom.h" + +#define IPU_FW_START_STOP_TIMEOUT 2000 +#define IPU_BOOT_CELL_RESET_TIMEOUT (2 * USEC_PER_SEC) +#define BOOT_STATE_IS_CRITICAL(s) IA_GOFO_FW_BOOT_STATE_IS_CRITICAL(s) +#define BOOT_STATE_IS_READY(s) ((s) == IA_GOFO_FW_BOOT_STATE_READY) +#define BOOT_STATE_IS_INACTIVE(s) ((s) == IA_GOFO_FW_BOOT_STATE_INACTIVE) + +struct ipu7_boot_context { + u32 base; + u32 dmem_address; + u32 status_ctrl_reg; + u32 fw_start_address_reg; + u32 fw_code_base_reg; +}; + +static const struct ipu7_boot_context contexts[IPU_SUBSYS_NUM] = { + { + /* ISYS */ + .dmem_address = IPU_ISYS_DMEM_OFFSET, + .status_ctrl_reg = BUTTRESS_REG_DRV_IS_UCX_CONTROL_STATUS, + .fw_start_address_reg = BUTTRESS_REG_DRV_IS_UCX_START_ADDR, + .fw_code_base_reg = IS_UC_CTRL_BASE + }, + { + /* PSYS */ + .dmem_address = IPU_PSYS_DMEM_OFFSET, + .status_ctrl_reg = BUTTRESS_REG_DRV_PS_UCX_CONTROL_STATUS, + .fw_start_address_reg = BUTTRESS_REG_DRV_PS_UCX_START_ADDR, + .fw_code_base_reg = PS_UC_CTRL_BASE + } +}; + +static u32 get_fw_boot_reg_addr(const struct ipu7_bus_device *adev, + enum ia_gofo_buttress_reg_id reg) +{ + u32 base = (adev->subsys == IPU_IS) ? 0U : (u32)IA_GOFO_FW_BOOT_ID_MAX; + + return BUTTRESS_FW_BOOT_PARAMS_ENTRY(base + (u32)reg); +} + +static void write_fw_boot_param(const struct ipu7_bus_device *adev, + enum ia_gofo_buttress_reg_id reg, + u32 val) +{ + void __iomem *base = adev->isp->base; + + dev_dbg(&adev->auxdev.dev, + "write boot param reg: %d addr: %x val: 0x%x\n", + reg, get_fw_boot_reg_addr(adev, reg), val); + writel(val, base + get_fw_boot_reg_addr(adev, reg)); +} + +static u32 read_fw_boot_param(const struct ipu7_bus_device *adev, + enum ia_gofo_buttress_reg_id reg) +{ + void __iomem *base = adev->isp->base; + + return readl(base + get_fw_boot_reg_addr(adev, reg)); +} + +static int ipu7_boot_cell_reset(const struct ipu7_bus_device *adev) +{ + const struct ipu7_boot_context *ctx = &contexts[adev->subsys]; + const struct device *dev = &adev->auxdev.dev; + u32 ucx_ctrl_status = ctx->status_ctrl_reg; + u32 timeout = IPU_BOOT_CELL_RESET_TIMEOUT; + void __iomem *base = adev->isp->base; + u32 val, val2; + int ret; + + dev_dbg(dev, "cell enter reset...\n"); + val = readl(base + ucx_ctrl_status); + dev_dbg(dev, "cell_ctrl_reg addr = 0x%x, val = 0x%x\n", + ucx_ctrl_status, val); + + dev_dbg(dev, "force cell reset...\n"); + val |= UCX_CTL_RESET; + val &= ~UCX_CTL_RUN; + + dev_dbg(dev, "write status_ctrl_reg(0x%x) to 0x%x\n", + ucx_ctrl_status, val); + writel(val, base + ucx_ctrl_status); + + ret = readl_poll_timeout(base + ucx_ctrl_status, val2, + (val2 & 0x3U) == (val & 0x3U), 100, timeout); + if (ret) { + dev_err(dev, "cell enter reset timeout. status: 0x%x\n", val2); + return -ETIMEDOUT; + } + + dev_dbg(dev, "cell exit reset...\n"); + val = readl(base + ucx_ctrl_status); + WARN((!(val & UCX_CTL_RESET) || val & UCX_CTL_RUN), + "cell status 0x%x", val); + + val &= ~(UCX_CTL_RESET | UCX_CTL_RUN); + dev_dbg(dev, "write status_ctrl_reg(0x%x) to 0x%x\n", + ucx_ctrl_status, val); + writel(val, base + ucx_ctrl_status); + + ret = readl_poll_timeout(base + ucx_ctrl_status, val2, + (val2 & 0x3U) == (val & 0x3U), 100, timeout); + if (ret) { + dev_err(dev, "cell exit reset timeout. status: 0x%x\n", val2); + return -ETIMEDOUT; + } + + return 0; +} + +static void ipu7_boot_cell_start(const struct ipu7_bus_device *adev) +{ + const struct ipu7_boot_context *ctx = &contexts[adev->subsys]; + void __iomem *base = adev->isp->base; + const struct device *dev = &adev->auxdev.dev; + u32 val; + + dev_dbg(dev, "starting cell...\n"); + val = readl(base + ctx->status_ctrl_reg); + WARN_ON(val & (UCX_CTL_RESET | UCX_CTL_RUN)); + + val &= ~UCX_CTL_RESET; + val |= UCX_CTL_RUN; + dev_dbg(dev, "write status_ctrl_reg(0x%x) to 0x%x\n", + ctx->status_ctrl_reg, val); + writel(val, base + ctx->status_ctrl_reg); +} + +static void ipu7_boot_cell_stop(const struct ipu7_bus_device *adev) +{ + const struct ipu7_boot_context *ctx = &contexts[adev->subsys]; + void __iomem *base = adev->isp->base; + const struct device *dev = &adev->auxdev.dev; + u32 val; + + dev_dbg(dev, "stopping cell...\n"); + + val = readl(base + ctx->status_ctrl_reg); + val &= ~UCX_CTL_RUN; + dev_dbg(dev, "write status_ctrl_reg(0x%x) to 0x%x\n", + ctx->status_ctrl_reg, val); + writel(val, base + ctx->status_ctrl_reg); + + /* Wait for uC transactions complete */ + usleep_range(10, 20); + + val = readl(base + ctx->status_ctrl_reg); + val |= UCX_CTL_RESET; + dev_dbg(dev, "write status_ctrl_reg(0x%x) to 0x%x\n", + ctx->status_ctrl_reg, val); + writel(val, base + ctx->status_ctrl_reg); +} + +static int ipu7_boot_cell_init(const struct ipu7_bus_device *adev) +{ + const struct ipu7_boot_context *ctx = &contexts[adev->subsys]; + void __iomem *base = adev->isp->base; + + dev_dbg(&adev->auxdev.dev, "write fw_start_address_reg(0x%x) to 0x%x\n", + ctx->fw_start_address_reg, adev->fw_entry); + writel(adev->fw_entry, base + ctx->fw_start_address_reg); + + return ipu7_boot_cell_reset(adev); +} + +static void init_boot_config(struct ia_gofo_boot_config *boot_config, + u32 length, u8 major) +{ + /* syscom version, new syscom2 version */ + boot_config->length = length; + boot_config->config_version.major = 1U; + boot_config->config_version.minor = 0U; + boot_config->config_version.subminor = 0U; + boot_config->config_version.patch = 0U; + + /* msg version for task interface */ + boot_config->client_version_support.num_versions = 1U; + boot_config->client_version_support.versions[0].major = major; + boot_config->client_version_support.versions[0].minor = 0U; + boot_config->client_version_support.versions[0].subminor = 0U; + boot_config->client_version_support.versions[0].patch = 0U; +} + +int ipu7_boot_init_boot_config(struct ipu7_bus_device *adev, + struct syscom_queue_config *qconfigs, + int num_queues, u32 uc_freq, + dma_addr_t subsys_config, u8 major) +{ + u32 total_queue_size_aligned = 0; + struct ipu7_syscom_context *syscom = adev->syscom; + struct ia_gofo_boot_config *boot_config; + struct syscom_queue_params_config *cfgs; + struct device *dev = &adev->auxdev.dev; + struct syscom_config_s *syscfg; + dma_addr_t queue_mem_dma_ptr; + void *queue_mem_ptr; + unsigned int i; + + dev_dbg(dev, "boot config queues_nr: %d freq: %u sys_conf: 0x%pad\n", + num_queues, uc_freq, &subsys_config); + /* Allocate boot config. */ + adev->boot_config_size = + sizeof(*cfgs) * num_queues + sizeof(*boot_config); + adev->boot_config = ipu7_dma_alloc(adev, adev->boot_config_size, + &adev->boot_config_dma_addr, + GFP_KERNEL, 0); + if (!adev->boot_config) { + dev_err(dev, "Failed to allocate boot config.\n"); + return -ENOMEM; + } + + boot_config = adev->boot_config; + memset(boot_config, 0, sizeof(struct ia_gofo_boot_config)); + init_boot_config(boot_config, adev->boot_config_size, major); + boot_config->subsys_config = subsys_config; + + boot_config->uc_tile_frequency = uc_freq; + boot_config->uc_tile_frequency_units = + IA_GOFO_FW_BOOT_UC_FREQUENCY_UNITS_MHZ; + boot_config->syscom_context_config.max_output_queues = + syscom->num_output_queues; + boot_config->syscom_context_config.max_input_queues = + syscom->num_input_queues; + + ipu7_dma_sync_single(adev, adev->boot_config_dma_addr, + adev->boot_config_size); + + for (i = 0; i < num_queues; i++) { + u32 queue_size = qconfigs[i].max_capacity * + qconfigs[i].token_size_in_bytes; + + queue_size = ALIGN(queue_size, 64U); + total_queue_size_aligned += queue_size; + qconfigs[i].queue_size = queue_size; + } + + /* Allocate queue memory */ + syscom->queue_mem = ipu7_dma_alloc(adev, total_queue_size_aligned, + &syscom->queue_mem_dma_addr, + GFP_KERNEL, 0); + if (!syscom->queue_mem) { + dev_err(dev, "Failed to allocate queue memory.\n"); + return -ENOMEM; + } + syscom->queue_mem_size = total_queue_size_aligned; + + syscfg = &boot_config->syscom_context_config; + cfgs = ipu7_syscom_get_queue_config(syscfg); + queue_mem_ptr = syscom->queue_mem; + queue_mem_dma_ptr = syscom->queue_mem_dma_addr; + for (i = 0; i < num_queues; i++) { + cfgs[i].token_array_mem = queue_mem_dma_ptr; + cfgs[i].max_capacity = qconfigs[i].max_capacity; + cfgs[i].token_size_in_bytes = qconfigs[i].token_size_in_bytes; + qconfigs[i].token_array_mem = queue_mem_ptr; + queue_mem_dma_ptr += qconfigs[i].queue_size; + queue_mem_ptr += qconfigs[i].queue_size; + } + + ipu7_dma_sync_single(adev, syscom->queue_mem_dma_addr, + total_queue_size_aligned); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ipu7_boot_init_boot_config, "INTEL_IPU7"); + +void ipu7_boot_release_boot_config(struct ipu7_bus_device *adev) +{ + struct ipu7_syscom_context *syscom = adev->syscom; + + if (syscom->queue_mem) { + ipu7_dma_free(adev, syscom->queue_mem_size, + syscom->queue_mem, + syscom->queue_mem_dma_addr, 0); + syscom->queue_mem = NULL; + syscom->queue_mem_dma_addr = 0; + } + + if (adev->boot_config) { + ipu7_dma_free(adev, adev->boot_config_size, + adev->boot_config, + adev->boot_config_dma_addr, 0); + adev->boot_config = NULL; + adev->boot_config_dma_addr = 0; + } +} +EXPORT_SYMBOL_NS_GPL(ipu7_boot_release_boot_config, "INTEL_IPU7"); + +int ipu7_boot_start_fw(const struct ipu7_bus_device *adev) +{ + const struct device *dev = &adev->auxdev.dev; + u32 timeout = IPU_FW_START_STOP_TIMEOUT; + void __iomem *base = adev->isp->base; + u32 boot_state, last_boot_state; + u32 indices_addr, msg_ver, id; + int ret; + + ret = ipu7_boot_cell_init(adev); + if (ret) + return ret; + + dev_dbg(dev, "start booting fw...\n"); + /* store "uninit" state to syscom/boot state reg */ + write_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID, + IA_GOFO_FW_BOOT_STATE_UNINIT); + /* + * Set registers to zero + * (not strictly required, but recommended for diagnostics) + */ + write_fw_boot_param(adev, + IA_GOFO_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID, 0); + write_fw_boot_param(adev, IA_GOFO_FW_BOOT_MESSAGING_VERSION_ID, 0); + /* store firmware configuration address */ + write_fw_boot_param(adev, IA_GOFO_FW_BOOT_CONFIG_ID, + adev->boot_config_dma_addr); + + /* Kick uC, then wait for boot complete */ + ipu7_boot_cell_start(adev); + + last_boot_state = IA_GOFO_FW_BOOT_STATE_UNINIT; + while (timeout--) { + boot_state = read_fw_boot_param(adev, + IA_GOFO_FW_BOOT_STATE_ID); + if (boot_state != last_boot_state) { + dev_dbg(dev, "boot state changed from 0x%x to 0x%x\n", + last_boot_state, boot_state); + last_boot_state = boot_state; + } + if (BOOT_STATE_IS_CRITICAL(boot_state) || + BOOT_STATE_IS_READY(boot_state)) + break; + usleep_range(1000, 1200); + } + + if (BOOT_STATE_IS_CRITICAL(boot_state)) { + ipu7_dump_fw_error_log(adev); + dev_err(dev, "critical boot state error 0x%x\n", boot_state); + return -EINVAL; + } else if (!BOOT_STATE_IS_READY(boot_state)) { + dev_err(dev, "fw boot timeout. state: 0x%x\n", boot_state); + return -ETIMEDOUT; + } + dev_dbg(dev, "fw boot done.\n"); + + /* Get FW syscom queue indices addr */ + id = IA_GOFO_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID; + indices_addr = read_fw_boot_param(adev, id); + adev->syscom->queue_indices = base + indices_addr; + dev_dbg(dev, "fw queue indices offset is 0x%x\n", indices_addr); + + /* Get message version. */ + msg_ver = read_fw_boot_param(adev, + IA_GOFO_FW_BOOT_MESSAGING_VERSION_ID); + dev_dbg(dev, "ipu message version is 0x%08x\n", msg_ver); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ipu7_boot_start_fw, "INTEL_IPU7"); + +int ipu7_boot_stop_fw(const struct ipu7_bus_device *adev) +{ + const struct device *dev = &adev->auxdev.dev; + u32 timeout = IPU_FW_START_STOP_TIMEOUT; + u32 boot_state; + + boot_state = read_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID); + if (BOOT_STATE_IS_CRITICAL(boot_state) || + !BOOT_STATE_IS_READY(boot_state)) { + dev_err(dev, "fw not ready for shutdown, state 0x%x\n", + boot_state); + return -EBUSY; + } + + /* Issue shutdown to start shutdown process */ + dev_dbg(dev, "stopping fw...\n"); + write_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID, + IA_GOFO_FW_BOOT_STATE_SHUTDOWN_CMD); + while (timeout--) { + boot_state = read_fw_boot_param(adev, + IA_GOFO_FW_BOOT_STATE_ID); + if (BOOT_STATE_IS_CRITICAL(boot_state) || + BOOT_STATE_IS_INACTIVE(boot_state)) + break; + usleep_range(1000, 1200); + } + + if (BOOT_STATE_IS_CRITICAL(boot_state)) { + ipu7_dump_fw_error_log(adev); + dev_err(dev, "critical boot state error 0x%x\n", boot_state); + return -EINVAL; + } else if (!BOOT_STATE_IS_INACTIVE(boot_state)) { + dev_err(dev, "stop fw timeout. state: 0x%x\n", boot_state); + return -ETIMEDOUT; + } + + ipu7_boot_cell_stop(adev); + dev_dbg(dev, "stop fw done.\n"); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ipu7_boot_stop_fw, "INTEL_IPU7"); + +u32 ipu7_boot_get_boot_state(const struct ipu7_bus_device *adev) +{ + return read_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID); +} +EXPORT_SYMBOL_NS_GPL(ipu7_boot_get_boot_state, "INTEL_IPU7"); diff --git a/drivers/staging/media/ipu7/ipu7-boot.h b/drivers/staging/media/ipu7/ipu7-boot.h new file mode 100644 index 0000000000000..5600be849931d --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-boot.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2022 - 2025 Intel Corporation + */ + +#ifndef IPU7_BOOT_H +#define IPU7_BOOT_H + +#include <linux/types.h> + +struct ipu7_bus_device; +struct syscom_queue_config; + +#define FW_QUEUE_CONFIG_SIZE(num_queues) \ + (sizeof(struct syscom_queue_config) * (num_queues)) + +int ipu7_boot_init_boot_config(struct ipu7_bus_device *adev, + struct syscom_queue_config *qconfigs, + int num_queues, u32 uc_freq, + dma_addr_t subsys_config, u8 major); +void ipu7_boot_release_boot_config(struct ipu7_bus_device *adev); +int ipu7_boot_start_fw(const struct ipu7_bus_device *adev); +int ipu7_boot_stop_fw(const struct ipu7_bus_device *adev); +u32 ipu7_boot_get_boot_state(const struct ipu7_bus_device *adev); +#endif diff --git a/drivers/staging/media/ipu7/ipu7-bus.c b/drivers/staging/media/ipu7/ipu7-bus.c new file mode 100644 index 0000000000000..7da44fde002af --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-bus.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <linux/auxiliary_bus.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/pci.h> +#include <linux/pm_domain.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> + +#include "ipu7.h" +#include "ipu7-bus.h" +#include "ipu7-boot.h" +#include "ipu7-dma.h" + +static int bus_pm_runtime_suspend(struct device *dev) +{ + struct ipu7_bus_device *adev = to_ipu7_bus_device(dev); + int ret; + + ret = pm_generic_runtime_suspend(dev); + if (ret) + return ret; + + ret = ipu_buttress_powerdown(dev, adev->ctrl); + if (!ret) + return 0; + + dev_err(dev, "power down failed!\n"); + + /* Powering down failed, attempt to resume device now */ + ret = pm_generic_runtime_resume(dev); + if (!ret) + return -EBUSY; + + return -EIO; +} + +static int bus_pm_runtime_resume(struct device *dev) +{ + struct ipu7_bus_device *adev = to_ipu7_bus_device(dev); + int ret; + + ret = ipu_buttress_powerup(dev, adev->ctrl); + if (ret) + return ret; + + ret = pm_generic_runtime_resume(dev); + if (ret) + goto out_err; + + return 0; + +out_err: + ipu_buttress_powerdown(dev, adev->ctrl); + + return -EBUSY; +} + +static struct dev_pm_domain ipu7_bus_pm_domain = { + .ops = { + .runtime_suspend = bus_pm_runtime_suspend, + .runtime_resume = bus_pm_runtime_resume, + }, +}; + +static DEFINE_MUTEX(ipu7_bus_mutex); +static void ipu7_bus_release(struct device *dev) +{ + struct ipu7_bus_device *adev = to_ipu7_bus_device(dev); + + kfree(adev->pdata); + kfree(adev); +} + +struct ipu7_bus_device * +ipu7_bus_initialize_device(struct pci_dev *pdev, struct device *parent, + void *pdata, const struct ipu_buttress_ctrl *ctrl, + const char *name) +{ + struct auxiliary_device *auxdev; + struct ipu7_bus_device *adev; + struct ipu7_device *isp = pci_get_drvdata(pdev); + int ret; + + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) + return ERR_PTR(-ENOMEM); + + adev->isp = isp; + adev->ctrl = ctrl; + adev->pdata = pdata; + auxdev = &adev->auxdev; + auxdev->name = name; + auxdev->id = (pci_domain_nr(pdev->bus) << 16) | + PCI_DEVID(pdev->bus->number, pdev->devfn); + + auxdev->dev.parent = parent; + auxdev->dev.release = ipu7_bus_release; + + ret = auxiliary_device_init(auxdev); + if (ret < 0) { + dev_err(&isp->pdev->dev, "auxiliary device init failed (%d)\n", + ret); + kfree(adev); + return ERR_PTR(ret); + } + + dev_pm_domain_set(&auxdev->dev, &ipu7_bus_pm_domain); + + pm_runtime_forbid(&adev->auxdev.dev); + pm_runtime_enable(&adev->auxdev.dev); + + return adev; +} + +int ipu7_bus_add_device(struct ipu7_bus_device *adev) +{ + struct auxiliary_device *auxdev = &adev->auxdev; + int ret; + + ret = auxiliary_device_add(auxdev); + if (ret) { + auxiliary_device_uninit(auxdev); + return ret; + } + + mutex_lock(&ipu7_bus_mutex); + list_add(&adev->list, &adev->isp->devices); + mutex_unlock(&ipu7_bus_mutex); + + pm_runtime_allow(&auxdev->dev); + + return 0; +} + +void ipu7_bus_del_devices(struct pci_dev *pdev) +{ + struct ipu7_device *isp = pci_get_drvdata(pdev); + struct ipu7_bus_device *adev, *save; + + mutex_lock(&ipu7_bus_mutex); + + list_for_each_entry_safe(adev, save, &isp->devices, list) { + pm_runtime_disable(&adev->auxdev.dev); + list_del(&adev->list); + auxiliary_device_delete(&adev->auxdev); + auxiliary_device_uninit(&adev->auxdev); + } + + mutex_unlock(&ipu7_bus_mutex); +} diff --git a/drivers/staging/media/ipu7/ipu7-bus.h b/drivers/staging/media/ipu7/ipu7-bus.h new file mode 100644 index 0000000000000..45157df16e909 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-bus.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#ifndef IPU7_BUS_H +#define IPU7_BUS_H + +#include <linux/auxiliary_bus.h> +#include <linux/container_of.h> +#include <linux/device.h> +#include <linux/irqreturn.h> +#include <linux/list.h> +#include <linux/scatterlist.h> +#include <linux/types.h> + +#include "abi/ipu7_fw_boot_abi.h" + +#include "ipu7-syscom.h" + +struct pci_dev; +struct ipu_buttress_ctrl; +struct ipu7_mmu; +struct ipu7_device; + +enum ipu7_subsys { + IPU_IS = 0, + IPU_PS = 1, + IPU_SUBSYS_NUM = 2, +}; + +struct ipu7_bus_device { + struct auxiliary_device auxdev; + const struct auxiliary_driver *auxdrv; + const struct ipu7_auxdrv_data *auxdrv_data; + struct list_head list; + enum ipu7_subsys subsys; + void *pdata; + struct ipu7_mmu *mmu; + struct ipu7_device *isp; + const struct ipu_buttress_ctrl *ctrl; + u64 dma_mask; + struct sg_table fw_sgt; + u32 fw_entry; + struct ipu7_syscom_context *syscom; + struct ia_gofo_boot_config *boot_config; + dma_addr_t boot_config_dma_addr; + u32 boot_config_size; +}; + +struct ipu7_auxdrv_data { + irqreturn_t (*isr)(struct ipu7_bus_device *adev); + irqreturn_t (*isr_threaded)(struct ipu7_bus_device *adev); + bool wake_isr_thread; +}; + +#define to_ipu7_bus_device(_dev) \ + container_of(to_auxiliary_dev(_dev), struct ipu7_bus_device, auxdev) +#define auxdev_to_adev(_auxdev) \ + container_of(_auxdev, struct ipu7_bus_device, auxdev) +#define ipu7_bus_get_drvdata(adev) dev_get_drvdata(&(adev)->auxdev.dev) + +struct ipu7_bus_device * +ipu7_bus_initialize_device(struct pci_dev *pdev, struct device *parent, + void *pdata, const struct ipu_buttress_ctrl *ctrl, + const char *name); +int ipu7_bus_add_device(struct ipu7_bus_device *adev); +void ipu7_bus_del_devices(struct pci_dev *pdev); +#endif diff --git a/drivers/staging/media/ipu7/ipu7-buttress-regs.h b/drivers/staging/media/ipu7/ipu7-buttress-regs.h new file mode 100644 index 0000000000000..3eafd6a3813d9 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-buttress-regs.h @@ -0,0 +1,461 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 - 2025 Intel Corporation + */ + +#ifndef IPU7_BUTTRESS_REGS_H +#define IPU7_BUTTRESS_REGS_H + +#define BUTTRESS_REG_IRQ_STATUS 0x2000 +#define BUTTRESS_REG_IRQ_STATUS_UNMASKED 0x2004 +#define BUTTRESS_REG_IRQ_ENABLE 0x2008 +#define BUTTRESS_REG_IRQ_CLEAR 0x200c +#define BUTTRESS_REG_IRQ_MASK 0x2010 +#define BUTTRESS_REG_TSC_CMD 0x2014 +#define BUTTRESS_REG_TSC_CTL 0x2018 +#define BUTTRESS_REG_TSC_LO 0x201c +#define BUTTRESS_REG_TSC_HI 0x2020 + +/* valid for PTL */ +#define BUTTRESS_REG_PB_TIMESTAMP_LO 0x2030 +#define BUTTRESS_REG_PB_TIMESTAMP_HI 0x2034 +#define BUTTRESS_REG_PB_TIMESTAMP_VALID 0x2038 + +#define BUTTRESS_REG_PS_WORKPOINT_REQ 0x2100 +#define BUTTRESS_REG_IS_WORKPOINT_REQ 0x2104 +#define BUTTRESS_REG_PS_WORKPOINT_DOMAIN_REQ 0x2108 +#define BUTTRESS_REG_PS_DOMAINS_STATUS 0x2110 +#define BUTTRESS_REG_PWR_STATUS 0x2114 +#define BUTTRESS_REG_PS_WORKPOINT_REQ_SHADOW 0x2120 +#define BUTTRESS_REG_IS_WORKPOINT_REQ_SHADOW 0x2124 +#define BUTTRESS_REG_PS_WORKPOINT_DOMAIN_REQ_SHADOW 0x2128 +#define BUTTRESS_REG_ISPS_WORKPOINT_DOWNLOAD 0x212c +#define BUTTRESS_REG_PG_FLOW_OVERRIDE 0x2180 +#define BUTTRESS_REG_GLOBAL_OVERRIDE_UNGATE_CTL 0x2184 +#define BUTTRESS_REG_PWR_FSM_CTL 0x2188 +#define BUTTRESS_REG_IDLE_WDT 0x218c +#define BUTTRESS_REG_PS_PWR_DOMAIN_EVENTQ_EN 0x2190 +#define BUTTRESS_REG_PS_PWR_DOMAIN_EVENTQ_ADDR 0x2194 +#define BUTTRESS_REG_PS_PWR_DOMAIN_EVENTQ_DATA 0x2198 +#define BUTTRESS_REG_POWER_EN_DELAY 0x219c +#define IPU7_BUTTRESS_REG_LTR_CONTROL 0x21a0 +#define IPU7_BUTTRESS_REG_NDE_CONTROL 0x21a4 +#define IPU7_BUTTRESS_REG_INT_FRM_PUNIT 0x21a8 +#define IPU8_BUTTRESS_REG_LTR_CONTROL 0x21a4 +#define IPU8_BUTTRESS_REG_NDE_CONTROL 0x21a8 +#define IPU8_BUTTRESS_REG_INT_FRM_PUNIT 0x21ac +#define BUTTRESS_REG_SLEEP_LEVEL_CFG 0x21b0 +#define BUTTRESS_REG_SLEEP_LEVEL_STS 0x21b4 +#define BUTTRESS_REG_DVFS_FSM_STATUS 0x21b8 +#define BUTTRESS_REG_PS_PLL_ENABLE 0x21bc +#define BUTTRESS_REG_D2D_CTL 0x21d4 +#define BUTTRESS_REG_IB_CLK_CTL 0x21d8 +#define BUTTRESS_REG_IB_CRO_CLK_CTL 0x21dc +#define BUTTRESS_REG_FUNC_FUSES 0x21e0 +#define BUTTRESS_REG_ISOCH_CTL 0x21e4 +#define BUTTRESS_REG_WORKPOINT_CTL 0x21f0 +#define BUTTRESS_REG_DRV_IS_UCX_CONTROL_STATUS 0x2200 +#define BUTTRESS_REG_DRV_IS_UCX_START_ADDR 0x2204 +#define BUTTRESS_REG_DRV_PS_UCX_CONTROL_STATUS 0x2208 +#define BUTTRESS_REG_DRV_PS_UCX_START_ADDR 0x220c +#define BUTTRESS_REG_DRV_UCX_RESET_CFG 0x2210 + +/* configured by CSE */ +#define BUTTRESS_REG_CSE_IS_UCX_CONTROL_STATUS 0x2300 +#define BUTTRESS_REG_CSE_IS_UCX_START_ADDR 0x2304 +#define BUTTRESS_REG_CSE_PS_UCX_CONTROL_STATUS 0x2308 +#define BUTTRESS_REG_CSE_PS_UCX_START_ADDR 0x230c + +#define BUTTRESS_REG_CAMERA_MASK 0x2310 +#define BUTTRESS_REG_FW_CTL 0x2314 +#define BUTTRESS_REG_SECURITY_CTL 0x2318 +#define BUTTRESS_REG_FUNCTIONAL_FW_SETUP 0x231c +#define BUTTRESS_REG_FW_BASE 0x2320 +#define BUTTRESS_REG_FW_BASE_LIMIT 0x2324 +#define BUTTRESS_REG_FW_SCRATCH_BASE 0x2328 +#define BUTTRESS_REG_FW_SCRATCH_LIMIT 0x232c +#define BUTTRESS_REG_CSE_ACTION 0x2330 + +/* configured by SW */ +#define BUTTRESS_REG_FW_RESET_CTL 0x2334 +#define BUTTRESS_REG_FW_SOURCE_SIZE 0x2338 +#define BUTTRESS_REG_FW_SOURCE_BASE 0x233c + +#define BUTTRESS_REG_IPU_SEC_CP_LSB 0x2400 +#define BUTTRESS_REG_IPU_SEC_CP_MSB 0x2404 +#define BUTTRESS_REG_IPU_SEC_WAC_LSB 0x2408 +#define BUTTRESS_REG_IPU_SEC_WAC_MSB 0x240c +#define BUTTRESS_REG_IPU_SEC_RAC_LSB 0x2410 +#define BUTTRESS_REG_IPU_SEC_RAC_MSB 0x2414 +#define BUTTRESS_REG_IPU_DRV_CP_LSB 0x2418 +#define BUTTRESS_REG_IPU_DRV_CP_MSB 0x241c +#define BUTTRESS_REG_IPU_DRV_WAC_LSB 0x2420 +#define BUTTRESS_REG_IPU_DRV_WAC_MSB 0x2424 +#define BUTTRESS_REG_IPU_DRV_RAC_LSB 0x2428 +#define BUTTRESS_REG_IPU_DRV_RAC_MSB 0x242c +#define BUTTRESS_REG_IPU_FW_CP_LSB 0x2430 +#define BUTTRESS_REG_IPU_FW_CP_MSB 0x2434 +#define BUTTRESS_REG_IPU_FW_WAC_LSB 0x2438 +#define BUTTRESS_REG_IPU_FW_WAC_MSB 0x243c +#define BUTTRESS_REG_IPU_FW_RAC_LSB 0x2440 +#define BUTTRESS_REG_IPU_FW_RAC_MSB 0x2444 +#define BUTTRESS_REG_IPU_BIOS_SEC_CP_LSB 0x2448 +#define BUTTRESS_REG_IPU_BIOS_SEC_CP_MSB 0x244c +#define BUTTRESS_REG_IPU_BIOS_SEC_WAC_LSB 0x2450 +#define BUTTRESS_REG_IPU_BIOS_SEC_WAC_MSB 0x2454 +#define BUTTRESS_REG_IPU_BIOS_SEC_RAC_LSB 0x2458 +#define BUTTRESS_REG_IPU_BIOS_SEC_RAC_MSB 0x245c +#define BUTTRESS_REG_IPU_DFD_CP_LSB 0x2460 +#define BUTTRESS_REG_IPU_DFD_CP_MSB 0x2464 +#define BUTTRESS_REG_IPU_DFD_WAC_LSB 0x2468 +#define BUTTRESS_REG_IPU_DFD_WAC_MSB 0x246c +#define BUTTRESS_REG_IPU_DFD_RAC_LSB 0x2470 +#define BUTTRESS_REG_IPU_DFD_RAC_MSB 0x2474 +#define BUTTRESS_REG_CSE2IUDB0 0x2500 +#define BUTTRESS_REG_CSE2IUDATA0 0x2504 +#define BUTTRESS_REG_CSE2IUCSR 0x2508 +#define BUTTRESS_REG_IU2CSEDB0 0x250c +#define BUTTRESS_REG_IU2CSEDATA0 0x2510 +#define BUTTRESS_REG_IU2CSECSR 0x2514 +#define BUTTRESS_REG_CSE2IUDB0_CR_SHADOW 0x2520 +#define BUTTRESS_REG_CSE2IUDATA0_CR_SHADOW 0x2524 +#define BUTTRESS_REG_CSE2IUCSR_CR_SHADOW 0x2528 +#define BUTTRESS_REG_IU2CSEDB0_CR_SHADOW 0x252c +#define BUTTRESS_REG_DVFS_FSM_SURVIVABILITY 0x2900 +#define BUTTRESS_REG_FLOWS_FSM_SURVIVABILITY 0x2904 +#define BUTTRESS_REG_FABRICS_FSM_SURVIVABILITY 0x2908 +#define BUTTRESS_REG_PS_SUB1_PM_FSM_SURVIVABILITY 0x290c +#define BUTTRESS_REG_PS_SUB0_PM_FSM_SURVIVABILITY 0x2910 +#define BUTTRESS_REG_PS_PM_FSM_SURVIVABILITY 0x2914 +#define BUTTRESS_REG_IS_PM_FSM_SURVIVABILITY 0x2918 +#define BUTTRESS_REG_FLR_RST_FSM_SURVIVABILITY 0x291c +#define BUTTRESS_REG_FW_RST_FSM_SURVIVABILITY 0x2920 +#define BUTTRESS_REG_RESETPREP_FSM_SURVIVABILITY 0x2924 +#define BUTTRESS_REG_POWER_FSM_DOMAIN_STATUS 0x3000 +#define BUTTRESS_REG_IDLEREQ_STATUS1 0x3004 +#define BUTTRESS_REG_POWER_FSM_STATUS_IS_PS 0x3008 +#define BUTTRESS_REG_POWER_ACK_B_STATUS 0x300c +#define BUTTRESS_REG_DOMAIN_RETENTION_CTL 0x3010 +#define BUTTRESS_REG_CG_CTRL_BITS 0x3014 +#define BUTTRESS_REG_IS_IFC_STATUS0 0x3018 +#define BUTTRESS_REG_IS_IFC_STATUS1 0x301c +#define BUTTRESS_REG_PS_IFC_STATUS0 0x3020 +#define BUTTRESS_REG_PS_IFC_STATUS1 0x3024 +#define BUTTRESS_REG_BTRS_IFC_STATUS0 0x3028 +#define BUTTRESS_REG_BTRS_IFC_STATUS1 0x302c +#define BUTTRESS_REG_IPU_SKU 0x3030 +#define BUTTRESS_REG_PS_IDLEACK 0x3034 +#define BUTTRESS_REG_IS_IDLEACK 0x3038 +#define BUTTRESS_REG_SPARE_REGS_0 0x303c +#define BUTTRESS_REG_SPARE_REGS_1 0x3040 +#define BUTTRESS_REG_SPARE_REGS_2 0x3044 +#define BUTTRESS_REG_SPARE_REGS_3 0x3048 +#define BUTTRESS_REG_IUNIT_ACV 0x304c +#define BUTTRESS_REG_CHICKEN_BITS 0x3050 +#define BUTTRESS_REG_SBENDPOINT_CFG 0x3054 +#define BUTTRESS_REG_ECC_ERR_LOG 0x3058 +#define BUTTRESS_REG_POWER_FSM_STATUS 0x3070 +#define BUTTRESS_REG_RESET_FSM_STATUS 0x3074 +#define BUTTRESS_REG_IDLE_STATUS 0x3078 +#define BUTTRESS_REG_IDLEACK_STATUS 0x307c +#define BUTTRESS_REG_IPU_DEBUG 0x3080 + +#define BUTTRESS_REG_FW_BOOT_PARAMS0 0x4000 +#define BUTTRESS_REG_FW_BOOT_PARAMS1 0x4004 +#define BUTTRESS_REG_FW_BOOT_PARAMS2 0x4008 +#define BUTTRESS_REG_FW_BOOT_PARAMS3 0x400c +#define BUTTRESS_REG_FW_BOOT_PARAMS4 0x4010 +#define BUTTRESS_REG_FW_BOOT_PARAMS5 0x4014 +#define BUTTRESS_REG_FW_BOOT_PARAMS6 0x4018 +#define BUTTRESS_REG_FW_BOOT_PARAMS7 0x401c +#define BUTTRESS_REG_FW_BOOT_PARAMS8 0x4020 +#define BUTTRESS_REG_FW_BOOT_PARAMS9 0x4024 +#define BUTTRESS_REG_FW_BOOT_PARAMS10 0x4028 +#define BUTTRESS_REG_FW_BOOT_PARAMS11 0x402c +#define BUTTRESS_REG_FW_BOOT_PARAMS12 0x4030 +#define BUTTRESS_REG_FW_BOOT_PARAMS13 0x4034 +#define BUTTRESS_REG_FW_BOOT_PARAMS14 0x4038 +#define BUTTRESS_REG_FW_BOOT_PARAMS15 0x403c + +#define BUTTRESS_FW_BOOT_PARAMS_ENTRY(i) \ + (BUTTRESS_REG_FW_BOOT_PARAMS0 + ((i) * 4U)) +#define BUTTRESS_REG_FW_GP(i) (0x4040 + 0x4 * (i)) +#define BUTTRESS_REG_FPGA_SUPPORT(i) (0x40c0 + 0x4 * (i)) + +#define BUTTRESS_REG_FW_GP8 0x4060 +#define BUTTRESS_REG_FW_GP24 0x40a0 + +#define BUTTRESS_REG_GPIO_0_PADCFG_ADDR_CR 0x4100 +#define BUTTRESS_REG_GPIO_1_PADCFG_ADDR_CR 0x4104 +#define BUTTRESS_REG_GPIO_2_PADCFG_ADDR_CR 0x4108 +#define BUTTRESS_REG_GPIO_3_PADCFG_ADDR_CR 0x410c +#define BUTTRESS_REG_GPIO_4_PADCFG_ADDR_CR 0x4110 +#define BUTTRESS_REG_GPIO_5_PADCFG_ADDR_CR 0x4114 +#define BUTTRESS_REG_GPIO_6_PADCFG_ADDR_CR 0x4118 +#define BUTTRESS_REG_GPIO_7_PADCFG_ADDR_CR 0x411c +#define BUTTRESS_REG_GPIO_ENABLE 0x4140 +#define BUTTRESS_REG_GPIO_VALUE_CR 0x4144 + +#define BUTTRESS_REG_IS_MEM_CORRECTABLE_ERROR_STATUS 0x5000 +#define BUTTRESS_REG_IS_MEM_FATAL_ERROR_STATUS 0x5004 +#define BUTTRESS_REG_IS_MEM_NON_FATAL_ERROR_STATUS 0x5008 +#define BUTTRESS_REG_IS_MEM_CHECK_PASSED 0x500c +#define BUTTRESS_REG_IS_MEM_ERROR_INJECT 0x5010 +#define BUTTRESS_REG_IS_MEM_ERROR_CLEAR 0x5014 +#define BUTTRESS_REG_PS_MEM_CORRECTABLE_ERROR_STATUS 0x5040 +#define BUTTRESS_REG_PS_MEM_FATAL_ERROR_STATUS 0x5044 +#define BUTTRESS_REG_PS_MEM_NON_FATAL_ERROR_STATUS 0x5048 +#define BUTTRESS_REG_PS_MEM_CHECK_PASSED 0x504c +#define BUTTRESS_REG_PS_MEM_ERROR_INJECT 0x5050 +#define BUTTRESS_REG_PS_MEM_ERROR_CLEAR 0x5054 + +#define BUTTRESS_REG_IS_AB_REGION_MIN_ADDRESS(i) (0x6000 + 0x8 * (i)) +#define BUTTRESS_REG_IS_AB_REGION_MAX_ADDRESS(i) (0x6004 + 0x8 * (i)) +#define BUTTRESS_REG_IS_AB_VIOLATION_LOG0 0x6080 +#define BUTTRESS_REG_IS_AB_VIOLATION_LOG1 0x6084 +#define BUTTRESS_REG_PS_AB_REGION_MIN_ADDRESS(i) (0x6100 + 0x8 * (i)) +#define BUTTRESS_REG_PS_AB_REGION_MAX_ADDRESS0 (0x6104 + 0x8 * (i)) +#define BUTTRESS_REG_PS_AB_VIOLATION_LOG0 0x6180 +#define BUTTRESS_REG_PS_AB_VIOLATION_LOG1 0x6184 +#define BUTTRESS_REG_PS_DEBUG_AB_VIOLATION_LOG0 0x6200 +#define BUTTRESS_REG_PS_DEBUG_AB_VIOLATION_LOG1 0x6204 +#define BUTTRESS_REG_IS_DEBUG_AB_VIOLATION_LOG0 0x6208 +#define BUTTRESS_REG_IS_DEBUG_AB_VIOLATION_LOG1 0x620c +#define BUTTRESS_REG_IB_DVP_AB_VIOLATION_LOG0 0x6210 +#define BUTTRESS_REG_IB_DVP_AB_VIOLATION_LOG1 0x6214 +#define BUTTRESS_REG_IB_ATB2DTF_AB_VIOLATION_LOG0 0x6218 +#define BUTTRESS_REG_IB_ATB2DTF_AB_VIOLATION_LOG1 0x621c +#define BUTTRESS_REG_AB_ENABLE 0x6220 +#define BUTTRESS_REG_AB_DEFAULT_ACCESS 0x6230 + +/* Indicates CSE has received an IPU driver IPC transaction */ +#define BUTTRESS_IRQ_IPC_EXEC_DONE_BY_CSE BIT(0) +/* Indicates an IPC transaction from CSE has arrived */ +#define BUTTRESS_IRQ_IPC_FROM_CSE_IS_WAITING BIT(1) +/* Indicates a CSR update from CSE has arrived */ +#define BUTTRESS_IRQ_CSE_CSR_SET BIT(2) +/* Indicates an interrupt set by Punit (not in use at this time) */ +#define BUTTRESS_IRQ_PUNIT_2_IUNIT_IRQ BIT(3) +/* Indicates an SAI violation was detected on access to IB registers */ +#define BUTTRESS_IRQ_SAI_VIOLATION BIT(4) +/* Indicates a transaction to IS was not able to pass the access blocker */ +#define BUTTRESS_IRQ_IS_AB_VIOLATION BIT(5) +/* Indicates a transaction to PS was not able to pass the access blocker */ +#define BUTTRESS_IRQ_PS_AB_VIOLATION BIT(6) +/* Indicates an error response was detected by the IB config NoC */ +#define BUTTRESS_IRQ_IB_CFG_NOC_ERR_IRQ BIT(7) +/* Indicates an error response was detected by the IB data NoC */ +#define BUTTRESS_IRQ_IB_DATA_NOC_ERR_IRQ BIT(8) +/* Transaction to DVP regs was not able to pass the access blocker */ +#define BUTTRESS_IRQ_IB_DVP_AB_VIOLATION BIT(9) +/* Transaction to ATB2DTF regs was not able to pass the access blocker */ +#define BUTTRESS_IRQ_ATB2DTF_AB_VIOLATION BIT(10) +/* Transaction to IS debug regs was not able to pass the access blocker */ +#define BUTTRESS_IRQ_IS_DEBUG_AB_VIOLATION BIT(11) +/* Transaction to PS debug regs was not able to pass the access blocker */ +#define BUTTRESS_IRQ_PS_DEBUG_AB_VIOLATION BIT(12) +/* Indicates timeout occurred waiting for a response from a target */ +#define BUTTRESS_IRQ_IB_CFG_NOC_TIMEOUT_IRQ BIT(13) +/* Set when any correctable ECC error input wire to buttress is set */ +#define BUTTRESS_IRQ_ECC_CORRECTABLE BIT(14) +/* Any noncorrectable-nonfatal ECC error input wire to buttress is set */ +#define BUTTRESS_IRQ_ECC_NONCORRECTABLE_NONFATAL BIT(15) +/* Set when any noncorrectable-fatal ECC error input wire to buttress is set */ +#define BUTTRESS_IRQ_ECC_NONCORRECTABLE_FATAL BIT(16) +/* Set when timeout occurred waiting for a response from a target */ +#define BUTTRESS_IRQ_IS_CFG_NOC_TIMEOUT_IRQ BIT(17) +#define BUTTRESS_IRQ_PS_CFG_NOC_TIMEOUT_IRQ BIT(18) +#define BUTTRESS_IRQ_LB_CFG_NOC_TIMEOUT_IRQ BIT(19) +/* IS FW double exception event */ +#define BUTTRESS_IRQ_IS_UC_PFATAL_ERROR BIT(26) +/* PS FW double exception event */ +#define BUTTRESS_IRQ_PS_UC_PFATAL_ERROR BIT(27) +/* IS FW watchdog event */ +#define BUTTRESS_IRQ_IS_WATCHDOG BIT(28) +/* PS FW watchdog event */ +#define BUTTRESS_IRQ_PS_WATCHDOG BIT(29) +/* IS IRC irq out */ +#define BUTTRESS_IRQ_IS_IRQ BIT(30) +/* PS IRC irq out */ +#define BUTTRESS_IRQ_PS_IRQ BIT(31) + +/* buttress irq */ +#define BUTTRESS_PWR_STATUS_HH_STATE_IDLE 0U +#define BUTTRESS_PWR_STATUS_HH_STATE_IN_PRGS 1U +#define BUTTRESS_PWR_STATUS_HH_STATE_DONE 2U +#define BUTTRESS_PWR_STATUS_HH_STATE_ERR 3U + +#define BUTTRESS_TSC_CMD_START_TSC_SYNC BIT(0) +#define BUTTRESS_PWR_STATUS_HH_STATUS_SHIFT 11 +#define BUTTRESS_PWR_STATUS_HH_STATUS_MASK (0x3U << 11) +#define BUTTRESS_TSW_WA_SOFT_RESET BIT(8) +/* new for PTL */ +#define BUTTRESS_SEL_PB_TIMESTAMP BIT(9) +#define BUTTRESS_IRQS (BUTTRESS_IRQ_IS_IRQ | \ + BUTTRESS_IRQ_PS_IRQ | \ + BUTTRESS_IRQ_IPC_FROM_CSE_IS_WAITING | \ + BUTTRESS_IRQ_CSE_CSR_SET | \ + BUTTRESS_IRQ_IPC_EXEC_DONE_BY_CSE | \ + BUTTRESS_IRQ_PUNIT_2_IUNIT_IRQ) + +/* Iunit to CSE regs */ +#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_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 BIT(0) +#define BUTTRESS_CSE2IUDATA0_IPC_AUTH_RUN_DONE BIT(1) +#define BUTTRESS_CSE2IUDATA0_IPC_AUTH_REPLACE_DONE BIT(2) +#define BUTTRESS_CSE2IUDATA0_IPC_UPDATE_SECURE_TOUCH_DONE BIT(4) + +#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) + +/* 0x20 == NACK, 0xf == unknown command */ +#define BUTTRESS_CSE2IUDATA0_IPC_NACK 0xf20 +#define BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK 0xffff + +/* IS/PS freq control */ +#define BUTTRESS_IS_FREQ_CTL_RATIO_MASK 0xffU +#define BUTTRESS_PS_FREQ_CTL_RATIO_MASK 0xffU + +#define IPU7_IS_FREQ_MAX 450 +#define IPU7_IS_FREQ_MIN 50 +#define IPU7_PS_FREQ_MAX 750 +#define BUTTRESS_PS_FREQ_RATIO_STEP 25U +/* valid for IPU8 */ +#define BUTTRESS_IS_FREQ_RATIO_STEP 25U + +/* IS: 400mhz, PS: 500mhz */ +#define IPU7_IS_FREQ_CTL_DEFAULT_RATIO 0x1b +#define IPU7_PS_FREQ_CTL_DEFAULT_RATIO 0x14 +/* IS: 400mhz, PS: 400mhz */ +#define IPU8_IS_FREQ_CTL_DEFAULT_RATIO 0x10 +#define IPU8_PS_FREQ_CTL_DEFAULT_RATIO 0x10 + +#define IPU_FREQ_CTL_CDYN 0x80 +#define IPU_FREQ_CTL_RATIO_SHIFT 0x0 +#define IPU_FREQ_CTL_CDYN_SHIFT 0x8 + +/* buttree power status */ +#define IPU_BUTTRESS_PWR_STATE_IS_PWR_SHIFT 0 +#define IPU_BUTTRESS_PWR_STATE_IS_PWR_MASK \ + (0x3U << IPU_BUTTRESS_PWR_STATE_IS_PWR_SHIFT) + +#define IPU_BUTTRESS_PWR_STATE_PS_PWR_SHIFT 4 +#define IPU_BUTTRESS_PWR_STATE_PS_PWR_MASK \ + (0x3U << 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 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 PS_FSM_CG BIT(3) + +#define BUTTRESS_OVERRIDE_IS_CLK BIT(1) +#define BUTTRESS_OVERRIDE_PS_CLK BIT(2) +/* ps_pll only valid for ipu8 */ +#define BUTTRESS_OWN_ACK_PS_PLL BIT(8) +#define BUTTRESS_OWN_ACK_IS_CLK BIT(9) +#define BUTTRESS_OWN_ACK_PS_CLK BIT(10) + +/* FW reset ctrl */ +#define BUTTRESS_FW_RESET_CTL_START BIT(0) +#define BUTTRESS_FW_RESET_CTL_DONE BIT(1) + +/* security */ +#define BUTTRESS_SECURITY_CTL_FW_SECURE_MODE BIT(16) +#define BUTTRESS_SECURITY_CTL_FW_SETUP_MASK GENMASK(4, 0) + +#define BUTTRESS_SECURITY_CTL_FW_SETUP_DONE BIT(0) +#define BUTTRESS_SECURITY_CTL_AUTH_DONE BIT(1) +#define BUTTRESS_SECURITY_CTL_AUTH_FAILED BIT(3) + +/* D2D */ +#define BUTTRESS_D2D_PWR_EN BIT(0) +#define BUTTRESS_D2D_PWR_ACK BIT(4) + +/* NDE */ +#define NDE_VAL_MASK GENMASK(9, 0) +#define NDE_SCALE_MASK GENMASK(12, 10) +#define NDE_VALID_MASK BIT(13) +#define NDE_RESVEC_MASK GENMASK(19, 16) +#define NDE_IN_VBLANK_DIS_MASK BIT(31) + +#define BUTTRESS_NDE_VAL_ACTIVE 48 +#define BUTTRESS_NDE_SCALE_ACTIVE 2 +#define BUTTRESS_NDE_VALID_ACTIVE 1 + +#define BUTTRESS_NDE_VAL_DEFAULT 1023 +#define BUTTRESS_NDE_SCALE_DEFAULT 2 +#define BUTTRESS_NDE_VALID_DEFAULT 0 + +/* IS and PS UCX control */ +#define UCX_CTL_RESET BIT(0) +#define UCX_CTL_RUN BIT(1) +#define UCX_CTL_WAKEUP BIT(2) +#define UCX_CTL_SPARE GENMASK(7, 3) +#define UCX_STS_PWR GENMASK(17, 16) +#define UCX_STS_SLEEPING BIT(18) + +/* 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)) + +/* PB registers */ +#define INTERRUPT_STATUS 0x0 +#define BTRS_LOCAL_INTERRUPT_MASK 0x4 +#define GLOBAL_INTERRUPT_MASK 0x8 +#define HM_ATS 0xc +#define ATS_ERROR_LOG1 0x10 +#define ATS_ERROR_LOG2 0x14 +#define ATS_ERROR_CLEAR 0x18 +#define CFI_0_ERROR_LOG 0x1c +#define CFI_0_ERROR_CLEAR 0x20 +#define HASH_CONFIG 0x2c +#define TLBID_HASH_ENABLE_31_0 0x30 +#define TLBID_HASH_ENABLE_63_32 0x34 +#define TLBID_HASH_ENABLE_95_64 0x38 +#define TLBID_HASH_ENABLE_127_96 0x3c +#define CFI_1_ERROR_LOGGING 0x40 +#define CFI_1_ERROR_CLEAR 0x44 +#define IMR_ERROR_LOGGING_LOW 0x48 +#define IMR_ERROR_LOGGING_HIGH 0x4c +#define IMR_ERROR_CLEAR 0x50 +#define PORT_ARBITRATION_WEIGHTS 0x54 +#define IMR_ERROR_LOGGING_CFI_1_LOW 0x58 +#define IMR_ERROR_LOGGING_CFI_1_HIGH 0x5c +#define IMR_ERROR_CLEAR_CFI_1 0x60 +#define BAR2_MISC_CONFIG 0x64 +#define RSP_ID_CONFIG_AXI2CFI_0 0x68 +#define RSP_ID_CONFIG_AXI2CFI_1 0x6c +#define PB_DRIVER_PCODE_MAILBOX_STATUS 0x70 +#define PB_DRIVER_PCODE_MAILBOX_INTERFACE 0x74 +#define PORT_ARBITRATION_WEIGHTS_ATS 0x78 + +#endif /* IPU7_BUTTRESS_REGS_H */ diff --git a/drivers/staging/media/ipu7/ipu7-buttress.c b/drivers/staging/media/ipu7/ipu7-buttress.c new file mode 100644 index 0000000000000..e5707f5e300ba --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-buttress.c @@ -0,0 +1,1192 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <asm/cpu_device_id.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/completion.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/firmware.h> +#include <linux/interrupt.h> +#include <linux/iopoll.h> +#include <linux/math64.h> +#include <linux/mm.h> +#include <linux/mutex.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/pm_runtime.h> +#include <linux/scatterlist.h> +#include <linux/types.h> + +#include "ipu7.h" +#include "ipu7-bus.h" +#include "ipu7-buttress.h" +#include "ipu7-buttress-regs.h" + +#define BOOTLOADER_STATUS_OFFSET BUTTRESS_REG_FW_BOOT_PARAMS7 + +#define BOOTLOADER_MAGIC_KEY 0xb00710adU + +#define ENTRY BUTTRESS_IU2CSECSR_IPC_PEER_COMP_ACTIONS_RST_PHASE1 +#define EXIT BUTTRESS_IU2CSECSR_IPC_PEER_COMP_ACTIONS_RST_PHASE2 +#define QUERY BUTTRESS_IU2CSECSR_IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE + +#define BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX 10U + +#define BUTTRESS_POWER_TIMEOUT_US (200 * USEC_PER_MSEC) + +#define BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US (5 * USEC_PER_SEC) +#define BUTTRESS_CSE_AUTHENTICATE_TIMEOUT_US (10 * USEC_PER_SEC) +#define BUTTRESS_CSE_FWRESET_TIMEOUT_US (100 * USEC_PER_MSEC) + +#define BUTTRESS_IPC_TX_TIMEOUT_MS MSEC_PER_SEC +#define BUTTRESS_IPC_RX_TIMEOUT_MS MSEC_PER_SEC +#define BUTTRESS_IPC_VALIDITY_TIMEOUT_US (1 * USEC_PER_SEC) +#define BUTTRESS_TSC_SYNC_TIMEOUT_US (5 * USEC_PER_MSEC) + +#define BUTTRESS_IPC_RESET_RETRY 2000U +#define BUTTRESS_CSE_IPC_RESET_RETRY 4U +#define BUTTRESS_IPC_CMD_SEND_RETRY 1U + +struct ipu7_ipc_buttress_msg { + u32 cmd; + u32 expected_resp; + bool require_resp; + u8 cmd_size; +}; + +static const u32 ipu7_adev_irq_mask[2] = { + BUTTRESS_IRQ_IS_IRQ, + BUTTRESS_IRQ_PS_IRQ +}; + +int ipu_buttress_ipc_reset(struct ipu7_device *isp, + struct ipu_buttress_ipc *ipc) +{ + unsigned int retries = BUTTRESS_IPC_RESET_RETRY; + struct ipu_buttress *b = &isp->buttress; + struct device *dev = &isp->pdev->dev; + u32 val = 0, csr_in_clr; + + if (!isp->secure_mode) { + dev_dbg(dev, "Skip IPC reset for non-secure mode\n"); + return 0; + } + + mutex_lock(&b->ipc_mutex); + + /* Clear-by-1 CSR (all bits), corresponding internal states. */ + val = readl(isp->base + ipc->csr_in); + writel(val, isp->base + ipc->csr_in); + + /* Set peer CSR bit IPC_PEER_COMP_ACTIONS_RST_PHASE1 */ + writel(ENTRY, isp->base + ipc->csr_out); + /* + * Clear-by-1 all CSR bits EXCEPT following + * bits: + * A. IPC_PEER_COMP_ACTIONS_RST_PHASE1. + * B. IPC_PEER_COMP_ACTIONS_RST_PHASE2. + * C. Possibly custom bits, depending on + * their role. + */ + csr_in_clr = BUTTRESS_IU2CSECSR_IPC_PEER_DEASSERTED_REG_VALID_REQ | + BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID | + BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ | QUERY; + + do { + usleep_range(400, 500); + val = readl(isp->base + ipc->csr_in); + switch (val) { + case ENTRY | EXIT: + case ENTRY | EXIT | QUERY: + /* + * 1) Clear-by-1 CSR bits + * (IPC_PEER_COMP_ACTIONS_RST_PHASE1, + * IPC_PEER_COMP_ACTIONS_RST_PHASE2). + * 2) Set peer CSR bit + * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE. + */ + writel(ENTRY | EXIT, isp->base + ipc->csr_in); + writel(QUERY, isp->base + ipc->csr_out); + break; + case ENTRY: + case ENTRY | QUERY: + /* + * 1) Clear-by-1 CSR bits + * (IPC_PEER_COMP_ACTIONS_RST_PHASE1, + * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE). + * 2) Set peer CSR bit + * IPC_PEER_COMP_ACTIONS_RST_PHASE1. + */ + writel(ENTRY | QUERY, isp->base + ipc->csr_in); + writel(ENTRY, isp->base + ipc->csr_out); + break; + case EXIT: + case EXIT | QUERY: + /* + * Clear-by-1 CSR bit + * IPC_PEER_COMP_ACTIONS_RST_PHASE2. + * 1) Clear incoming doorbell. + * 2) Clear-by-1 all CSR bits EXCEPT following + * bits: + * A. IPC_PEER_COMP_ACTIONS_RST_PHASE1. + * B. IPC_PEER_COMP_ACTIONS_RST_PHASE2. + * C. Possibly custom bits, depending on + * their role. + * 3) Set peer CSR bit + * IPC_PEER_COMP_ACTIONS_RST_PHASE2. + */ + writel(EXIT, isp->base + ipc->csr_in); + writel(0, isp->base + ipc->db0_in); + writel(csr_in_clr, isp->base + ipc->csr_in); + writel(EXIT, isp->base + ipc->csr_out); + + /* + * Read csr_in again to make sure if RST_PHASE2 is done. + * If csr_in is QUERY, it should be handled again. + */ + usleep_range(200, 300); + val = readl(isp->base + ipc->csr_in); + if (val & QUERY) { + dev_dbg(dev, + "RST_PHASE2 retry csr_in = %x\n", val); + break; + } + mutex_unlock(&b->ipc_mutex); + return 0; + case QUERY: + /* + * 1) Clear-by-1 CSR bit + * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE. + * 2) Set peer CSR bit + * IPC_PEER_COMP_ACTIONS_RST_PHASE1 + */ + writel(QUERY, isp->base + ipc->csr_in); + writel(ENTRY, isp->base + ipc->csr_out); + break; + default: + dev_dbg_ratelimited(dev, "Unexpected CSR 0x%x\n", val); + break; + } + } while (retries--); + + mutex_unlock(&b->ipc_mutex); + dev_err(dev, "Timed out while waiting for CSE\n"); + + return -ETIMEDOUT; +} + +static void ipu_buttress_ipc_validity_close(struct ipu7_device *isp, + struct ipu_buttress_ipc *ipc) +{ + writel(BUTTRESS_IU2CSECSR_IPC_PEER_DEASSERTED_REG_VALID_REQ, + isp->base + ipc->csr_out); +} + +static int +ipu_buttress_ipc_validity_open(struct ipu7_device *isp, + struct ipu_buttress_ipc *ipc) +{ + unsigned int mask = BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID; + void __iomem *addr; + int ret; + u32 val; + + writel(BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ, + isp->base + ipc->csr_out); + + addr = isp->base + ipc->csr_in; + ret = readl_poll_timeout(addr, val, val & mask, 200, + BUTTRESS_IPC_VALIDITY_TIMEOUT_US); + if (ret) { + dev_err(&isp->pdev->dev, "CSE validity timeout 0x%x\n", val); + ipu_buttress_ipc_validity_close(isp, ipc); + } + + return ret; +} + +static void ipu_buttress_ipc_recv(struct ipu7_device *isp, + struct ipu_buttress_ipc *ipc, u32 *ipc_msg) +{ + if (ipc_msg) + *ipc_msg = readl(isp->base + ipc->data0_in); + writel(0, isp->base + ipc->db0_in); +} + +static int ipu_buttress_ipc_send_msg(struct ipu7_device *isp, + struct ipu7_ipc_buttress_msg *msg) +{ + unsigned long tx_timeout_jiffies, rx_timeout_jiffies; + unsigned int retry = BUTTRESS_IPC_CMD_SEND_RETRY; + struct ipu_buttress *b = &isp->buttress; + struct ipu_buttress_ipc *ipc = &b->cse; + struct device *dev = &isp->pdev->dev; + int tout; + u32 val; + int ret; + + mutex_lock(&b->ipc_mutex); + + ret = ipu_buttress_ipc_validity_open(isp, ipc); + if (ret) { + dev_err(dev, "IPC validity open failed\n"); + goto out; + } + + tx_timeout_jiffies = msecs_to_jiffies(BUTTRESS_IPC_TX_TIMEOUT_MS); + rx_timeout_jiffies = msecs_to_jiffies(BUTTRESS_IPC_RX_TIMEOUT_MS); + +try: + reinit_completion(&ipc->send_complete); + if (msg->require_resp) + reinit_completion(&ipc->recv_complete); + + dev_dbg(dev, "IPC command: 0x%x\n", msg->cmd); + writel(msg->cmd, isp->base + ipc->data0_out); + val = BUTTRESS_IU2CSEDB0_BUSY | msg->cmd_size; + writel(val, isp->base + ipc->db0_out); + + tout = wait_for_completion_timeout(&ipc->send_complete, + tx_timeout_jiffies); + if (!tout) { + dev_err(dev, "send IPC response timeout\n"); + if (!retry--) { + ret = -ETIMEDOUT; + goto out; + } + + /* Try again if CSE is not responding on first try */ + writel(0, isp->base + ipc->db0_out); + goto try; + } + + if (!msg->require_resp) { + ret = -EIO; + goto out; + } + + tout = wait_for_completion_timeout(&ipc->recv_complete, + rx_timeout_jiffies); + if (!tout) { + dev_err(dev, "recv IPC response timeout\n"); + ret = -ETIMEDOUT; + goto out; + } + + if (ipc->nack_mask && + (ipc->recv_data & ipc->nack_mask) == ipc->nack) { + dev_err(dev, "IPC NACK for cmd 0x%x\n", msg->cmd); + ret = -EIO; + goto out; + } + + if (ipc->recv_data != msg->expected_resp) { + dev_err(dev, + "expected resp: 0x%x, IPC response: 0x%x\n", + msg->expected_resp, ipc->recv_data); + ret = -EIO; + goto out; + } + + dev_dbg(dev, "IPC commands done\n"); + +out: + ipu_buttress_ipc_validity_close(isp, ipc); + mutex_unlock(&b->ipc_mutex); + + return ret; +} + +static int ipu_buttress_ipc_send(struct ipu7_device *isp, + u32 ipc_msg, u32 size, bool require_resp, + u32 expected_resp) +{ + struct ipu7_ipc_buttress_msg msg = { + .cmd = ipc_msg, + .cmd_size = size, + .require_resp = require_resp, + .expected_resp = expected_resp, + }; + + return ipu_buttress_ipc_send_msg(isp, &msg); +} + +static irqreturn_t ipu_buttress_call_isr(struct ipu7_bus_device *adev) +{ + irqreturn_t ret = IRQ_WAKE_THREAD; + + if (!adev || !adev->auxdrv || !adev->auxdrv_data) + return IRQ_NONE; + + if (adev->auxdrv_data->isr) + ret = adev->auxdrv_data->isr(adev); + + if (ret == IRQ_WAKE_THREAD && !adev->auxdrv_data->isr_threaded) + ret = IRQ_NONE; + + return ret; +} + +irqreturn_t ipu_buttress_isr(int irq, void *isp_ptr) +{ + struct ipu7_device *isp = isp_ptr; + struct ipu7_bus_device *adev[] = { isp->isys, isp->psys }; + struct ipu_buttress *b = &isp->buttress; + struct device *dev = &isp->pdev->dev; + irqreturn_t ret = IRQ_NONE; + u32 pb_irq, pb_local_irq; + u32 disable_irqs = 0; + u32 irq_status; + unsigned int i; + + pm_runtime_get_noresume(dev); + + pb_irq = readl(isp->pb_base + INTERRUPT_STATUS); + writel(pb_irq, isp->pb_base + INTERRUPT_STATUS); + + /* check btrs ATS, CFI and IMR errors, BIT(0) is unused for IPU */ + pb_local_irq = readl(isp->pb_base + BTRS_LOCAL_INTERRUPT_MASK); + if (pb_local_irq & ~BIT(0)) { + dev_warn(dev, "PB interrupt status 0x%x local 0x%x\n", pb_irq, + pb_local_irq); + dev_warn(dev, "Details: %x %x %x %x %x %x %x %x\n", + readl(isp->pb_base + ATS_ERROR_LOG1), + readl(isp->pb_base + ATS_ERROR_LOG2), + readl(isp->pb_base + CFI_0_ERROR_LOG), + readl(isp->pb_base + CFI_1_ERROR_LOGGING), + readl(isp->pb_base + IMR_ERROR_LOGGING_LOW), + readl(isp->pb_base + IMR_ERROR_LOGGING_HIGH), + readl(isp->pb_base + IMR_ERROR_LOGGING_CFI_1_LOW), + readl(isp->pb_base + IMR_ERROR_LOGGING_CFI_1_HIGH)); + } + + irq_status = readl(isp->base + BUTTRESS_REG_IRQ_STATUS); + if (!irq_status) { + pm_runtime_put_noidle(dev); + return IRQ_NONE; + } + + do { + writel(irq_status, isp->base + BUTTRESS_REG_IRQ_CLEAR); + + for (i = 0; i < ARRAY_SIZE(ipu7_adev_irq_mask); i++) { + irqreturn_t r = ipu_buttress_call_isr(adev[i]); + + if (!(irq_status & ipu7_adev_irq_mask[i])) + continue; + + if (r == IRQ_WAKE_THREAD) { + ret = IRQ_WAKE_THREAD; + disable_irqs |= ipu7_adev_irq_mask[i]; + } else if (ret == IRQ_NONE && r == IRQ_HANDLED) { + ret = IRQ_HANDLED; + } + } + + if (irq_status & (BUTTRESS_IRQS | BUTTRESS_IRQ_SAI_VIOLATION) && + ret == IRQ_NONE) + ret = IRQ_HANDLED; + + if (irq_status & BUTTRESS_IRQ_IPC_FROM_CSE_IS_WAITING) { + dev_dbg(dev, "BUTTRESS_IRQ_IPC_FROM_CSE_IS_WAITING\n"); + ipu_buttress_ipc_recv(isp, &b->cse, &b->cse.recv_data); + complete(&b->cse.recv_complete); + } + + if (irq_status & BUTTRESS_IRQ_CSE_CSR_SET) + dev_dbg(dev, "BUTTRESS_IRQ_CSE_CSR_SET\n"); + + if (irq_status & BUTTRESS_IRQ_IPC_EXEC_DONE_BY_CSE) { + dev_dbg(dev, "BUTTRESS_IRQ_IPC_EXEC_DONE_BY_CSE\n"); + complete(&b->cse.send_complete); + } + + if (irq_status & BUTTRESS_IRQ_PUNIT_2_IUNIT_IRQ) + dev_dbg(dev, "BUTTRESS_IRQ_PUNIT_2_IUNIT_IRQ\n"); + + if (irq_status & BUTTRESS_IRQ_SAI_VIOLATION && + ipu_buttress_get_secure_mode(isp)) + dev_err(dev, "BUTTRESS_IRQ_SAI_VIOLATION\n"); + + irq_status = readl(isp->base + BUTTRESS_REG_IRQ_STATUS); + } while (irq_status); + + if (disable_irqs) + writel(BUTTRESS_IRQS & ~disable_irqs, + isp->base + BUTTRESS_REG_IRQ_ENABLE); + + pm_runtime_put(dev); + + return ret; +} + +irqreturn_t ipu_buttress_isr_threaded(int irq, void *isp_ptr) +{ + struct ipu7_device *isp = isp_ptr; + struct ipu7_bus_device *adev[] = { isp->isys, isp->psys }; + const struct ipu7_auxdrv_data *drv_data = NULL; + irqreturn_t ret = IRQ_NONE; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ipu7_adev_irq_mask) && adev[i]; i++) { + drv_data = adev[i]->auxdrv_data; + if (!drv_data) + continue; + + if (drv_data->wake_isr_thread && + drv_data->isr_threaded(adev[i]) == IRQ_HANDLED) + ret = IRQ_HANDLED; + } + + writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_IRQ_ENABLE); + + return ret; +} + +static int isys_d2d_power(struct device *dev, bool on) +{ + struct ipu7_device *isp = to_ipu7_bus_device(dev)->isp; + int ret = 0; + u32 target = on ? BUTTRESS_D2D_PWR_ACK : 0U; + u32 val; + + dev_dbg(dev, "power %s isys d2d.\n", on ? "UP" : "DOWN"); + val = readl(isp->base + BUTTRESS_REG_D2D_CTL); + if ((val & BUTTRESS_D2D_PWR_ACK) == target) { + dev_info(dev, "d2d already in %s state.\n", + on ? "UP" : "DOWN"); + return 0; + } + + val = on ? val | BUTTRESS_D2D_PWR_EN : val & (~BUTTRESS_D2D_PWR_EN); + writel(val, isp->base + BUTTRESS_REG_D2D_CTL); + ret = readl_poll_timeout(isp->base + BUTTRESS_REG_D2D_CTL, + val, (val & BUTTRESS_D2D_PWR_ACK) == target, + 100, BUTTRESS_POWER_TIMEOUT_US); + if (ret) + dev_err(dev, "power %s d2d timeout. status: 0x%x\n", + on ? "UP" : "DOWN", val); + + return ret; +} + +static void isys_nde_control(struct device *dev, bool on) +{ + struct ipu7_device *isp = to_ipu7_bus_device(dev)->isp; + u32 val, value, scale, valid, resvec; + u32 nde_reg; + + if (on) { + value = BUTTRESS_NDE_VAL_ACTIVE; + scale = BUTTRESS_NDE_SCALE_ACTIVE; + valid = BUTTRESS_NDE_VALID_ACTIVE; + } else { + value = BUTTRESS_NDE_VAL_DEFAULT; + scale = BUTTRESS_NDE_SCALE_DEFAULT; + valid = BUTTRESS_NDE_VALID_DEFAULT; + } + + /* only set the fabrics resource ownership for ipu8 */ + nde_reg = is_ipu8(isp->hw_ver) ? IPU8_BUTTRESS_REG_NDE_CONTROL : + IPU7_BUTTRESS_REG_NDE_CONTROL; + resvec = is_ipu8(isp->hw_ver) ? 0x2 : 0xe; + val = FIELD_PREP(NDE_VAL_MASK, value) | + FIELD_PREP(NDE_SCALE_MASK, scale) | + FIELD_PREP(NDE_VALID_MASK, valid) | + FIELD_PREP(NDE_RESVEC_MASK, resvec); + + writel(val, isp->base + nde_reg); +} + +static int ipu7_buttress_powerup(struct device *dev, + const struct ipu_buttress_ctrl *ctrl) +{ + struct ipu7_device *isp = to_ipu7_bus_device(dev)->isp; + u32 val, exp_sts; + int ret = 0; + + if (!ctrl) + return 0; + + mutex_lock(&isp->buttress.power_mutex); + + exp_sts = ctrl->pwr_sts_on << ctrl->pwr_sts_shift; + if (ctrl->subsys_id == IPU_IS) { + ret = isys_d2d_power(dev, true); + if (ret) + goto out_power; + isys_nde_control(dev, true); + } + + /* request clock resource ownership */ + val = readl(isp->base + BUTTRESS_REG_SLEEP_LEVEL_CFG); + val |= ctrl->ovrd_clk; + writel(val, isp->base + BUTTRESS_REG_SLEEP_LEVEL_CFG); + ret = readl_poll_timeout(isp->base + BUTTRESS_REG_SLEEP_LEVEL_STS, + val, (val & ctrl->own_clk_ack), + 100, BUTTRESS_POWER_TIMEOUT_US); + if (ret) + dev_warn(dev, "request clk ownership timeout. status 0x%x\n", + val); + + val = ctrl->ratio << ctrl->ratio_shift | ctrl->cdyn << ctrl->cdyn_shift; + + dev_dbg(dev, "set 0x%x to %s_WORKPOINT_REQ.\n", val, + ctrl->subsys_id == IPU_IS ? "IS" : "PS"); + writel(val, isp->base + ctrl->freq_ctl); + + ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATUS, + val, ((val & ctrl->pwr_sts_mask) == exp_sts), + 100, BUTTRESS_POWER_TIMEOUT_US); + if (ret) { + dev_err(dev, "%s power up timeout with status: 0x%x\n", + ctrl->subsys_id == IPU_IS ? "IS" : "PS", val); + goto out_power; + } + + dev_dbg(dev, "%s power up successfully. status: 0x%x\n", + ctrl->subsys_id == IPU_IS ? "IS" : "PS", val); + + /* release clock resource ownership */ + val = readl(isp->base + BUTTRESS_REG_SLEEP_LEVEL_CFG); + val &= ~ctrl->ovrd_clk; + writel(val, isp->base + BUTTRESS_REG_SLEEP_LEVEL_CFG); + +out_power: + mutex_unlock(&isp->buttress.power_mutex); + + return ret; +} + +static int ipu7_buttress_powerdown(struct device *dev, + const struct ipu_buttress_ctrl *ctrl) +{ + struct ipu7_device *isp = to_ipu7_bus_device(dev)->isp; + u32 val, exp_sts; + int ret = 0; + + if (!ctrl) + return 0; + + mutex_lock(&isp->buttress.power_mutex); + + exp_sts = ctrl->pwr_sts_off << ctrl->pwr_sts_shift; + val = 0x8U << ctrl->ratio_shift; + + dev_dbg(dev, "set 0x%x to %s_WORKPOINT_REQ.\n", val, + ctrl->subsys_id == IPU_IS ? "IS" : "PS"); + writel(val, isp->base + ctrl->freq_ctl); + ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATUS, + val, ((val & ctrl->pwr_sts_mask) == exp_sts), + 100, BUTTRESS_POWER_TIMEOUT_US); + if (ret) { + dev_err(dev, "%s power down timeout with status: 0x%x\n", + ctrl->subsys_id == IPU_IS ? "IS" : "PS", val); + goto out_power; + } + + dev_dbg(dev, "%s power down successfully. status: 0x%x\n", + ctrl->subsys_id == IPU_IS ? "IS" : "PS", val); +out_power: + if (ctrl->subsys_id == IPU_IS && !ret) { + isys_d2d_power(dev, false); + isys_nde_control(dev, false); + } + + mutex_unlock(&isp->buttress.power_mutex); + + return ret; +} + +static int ipu8_buttress_powerup(struct device *dev, + const struct ipu_buttress_ctrl *ctrl) +{ + struct ipu7_device *isp = to_ipu7_bus_device(dev)->isp; + u32 sleep_level_reg = BUTTRESS_REG_SLEEP_LEVEL_STS; + u32 val, exp_sts; + int ret = 0; + + if (!ctrl) + return 0; + + mutex_lock(&isp->buttress.power_mutex); + exp_sts = ctrl->pwr_sts_on << ctrl->pwr_sts_shift; + if (ctrl->subsys_id == IPU_IS) { + ret = isys_d2d_power(dev, true); + if (ret) + goto out_power; + isys_nde_control(dev, true); + } + + /* request ps_pll when psys freq > 400Mhz */ + if (ctrl->subsys_id == IPU_PS && ctrl->ratio > 0x10) { + writel(1, isp->base + BUTTRESS_REG_PS_PLL_ENABLE); + ret = readl_poll_timeout(isp->base + sleep_level_reg, + val, (val & ctrl->own_clk_ack), + 100, BUTTRESS_POWER_TIMEOUT_US); + if (ret) + dev_warn(dev, "ps_pll req ack timeout. status 0x%x\n", + val); + } + + val = ctrl->ratio << ctrl->ratio_shift | ctrl->cdyn << ctrl->cdyn_shift; + dev_dbg(dev, "set 0x%x to %s_WORKPOINT_REQ.\n", val, + ctrl->subsys_id == IPU_IS ? "IS" : "PS"); + writel(val, isp->base + ctrl->freq_ctl); + ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATUS, + val, ((val & ctrl->pwr_sts_mask) == exp_sts), + 100, BUTTRESS_POWER_TIMEOUT_US); + if (ret) { + dev_err(dev, "%s power up timeout with status: 0x%x\n", + ctrl->subsys_id == IPU_IS ? "IS" : "PS", val); + goto out_power; + } + + dev_dbg(dev, "%s power up successfully. status: 0x%x\n", + ctrl->subsys_id == IPU_IS ? "IS" : "PS", val); +out_power: + mutex_unlock(&isp->buttress.power_mutex); + + return ret; +} + +static int ipu8_buttress_powerdown(struct device *dev, + const struct ipu_buttress_ctrl *ctrl) +{ + struct ipu7_device *isp = to_ipu7_bus_device(dev)->isp; + u32 val, exp_sts; + int ret = 0; + + if (!ctrl) + return 0; + + mutex_lock(&isp->buttress.power_mutex); + exp_sts = ctrl->pwr_sts_off << ctrl->pwr_sts_shift; + + if (ctrl->subsys_id == IPU_PS) + val = 0x10U << ctrl->ratio_shift; + else + val = 0x8U << ctrl->ratio_shift; + + dev_dbg(dev, "set 0x%x to %s_WORKPOINT_REQ.\n", val, + ctrl->subsys_id == IPU_IS ? "IS" : "PS"); + writel(val, isp->base + ctrl->freq_ctl); + ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATUS, + val, ((val & ctrl->pwr_sts_mask) == exp_sts), + 100, BUTTRESS_POWER_TIMEOUT_US); + if (ret) { + dev_err(dev, "%s power down timeout with status: 0x%x\n", + ctrl->subsys_id == IPU_IS ? "IS" : "PS", val); + goto out_power; + } + + dev_dbg(dev, "%s power down successfully. status: 0x%x\n", + ctrl->subsys_id == IPU_IS ? "IS" : "PS", val); +out_power: + if (ctrl->subsys_id == IPU_IS && !ret) { + isys_d2d_power(dev, false); + isys_nde_control(dev, false); + } + + if (ctrl->subsys_id == IPU_PS) { + val = readl(isp->base + BUTTRESS_REG_SLEEP_LEVEL_STS); + if (val & ctrl->own_clk_ack) + writel(0, isp->base + BUTTRESS_REG_PS_PLL_ENABLE); + } + mutex_unlock(&isp->buttress.power_mutex); + + return ret; +} + +int ipu_buttress_powerup(struct device *dev, + const struct ipu_buttress_ctrl *ctrl) +{ + struct ipu7_device *isp = to_ipu7_bus_device(dev)->isp; + + if (is_ipu8(isp->hw_ver)) + return ipu8_buttress_powerup(dev, ctrl); + + return ipu7_buttress_powerup(dev, ctrl); +} + +int ipu_buttress_powerdown(struct device *dev, + const struct ipu_buttress_ctrl *ctrl) +{ + struct ipu7_device *isp = to_ipu7_bus_device(dev)->isp; + + if (is_ipu8(isp->hw_ver)) + return ipu8_buttress_powerdown(dev, ctrl); + + return ipu7_buttress_powerdown(dev, ctrl); +} + +bool ipu_buttress_get_secure_mode(struct ipu7_device *isp) +{ + u32 val; + + val = readl(isp->base + BUTTRESS_REG_SECURITY_CTL); + + return val & BUTTRESS_SECURITY_CTL_FW_SECURE_MODE; +} + +bool ipu_buttress_auth_done(struct ipu7_device *isp) +{ + u32 val; + + if (!isp->secure_mode) + return true; + + val = readl(isp->base + BUTTRESS_REG_SECURITY_CTL); + val = FIELD_GET(BUTTRESS_SECURITY_CTL_FW_SETUP_MASK, val); + + return val == BUTTRESS_SECURITY_CTL_AUTH_DONE; +} +EXPORT_SYMBOL_NS_GPL(ipu_buttress_auth_done, "INTEL_IPU7"); + +int ipu_buttress_get_isys_freq(struct ipu7_device *isp, u32 *freq) +{ + u32 reg_val; + int ret; + + ret = pm_runtime_get_sync(&isp->isys->auxdev.dev); + if (ret < 0) { + pm_runtime_put(&isp->isys->auxdev.dev); + dev_err(&isp->pdev->dev, "Runtime PM failed (%d)\n", ret); + return ret; + } + + reg_val = readl(isp->base + BUTTRESS_REG_IS_WORKPOINT_REQ); + + pm_runtime_put(&isp->isys->auxdev.dev); + + if (is_ipu8(isp->hw_ver)) + *freq = (reg_val & BUTTRESS_IS_FREQ_CTL_RATIO_MASK) * 25; + else + *freq = (reg_val & BUTTRESS_IS_FREQ_CTL_RATIO_MASK) * 50 / 3; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ipu_buttress_get_isys_freq, "INTEL_IPU7"); + +int ipu_buttress_get_psys_freq(struct ipu7_device *isp, u32 *freq) +{ + u32 reg_val; + int ret; + + ret = pm_runtime_get_sync(&isp->psys->auxdev.dev); + if (ret < 0) { + pm_runtime_put(&isp->psys->auxdev.dev); + dev_err(&isp->pdev->dev, "Runtime PM failed (%d)\n", ret); + return ret; + } + + reg_val = readl(isp->base + BUTTRESS_REG_PS_WORKPOINT_REQ); + + pm_runtime_put(&isp->psys->auxdev.dev); + + reg_val &= BUTTRESS_PS_FREQ_CTL_RATIO_MASK; + *freq = BUTTRESS_PS_FREQ_RATIO_STEP * reg_val; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ipu_buttress_get_psys_freq, "INTEL_IPU7"); + +int ipu_buttress_reset_authentication(struct ipu7_device *isp) +{ + struct device *dev = &isp->pdev->dev; + int ret; + u32 val; + + if (!isp->secure_mode) { + dev_dbg(dev, "Skip auth for non-secure mode\n"); + return 0; + } + + writel(BUTTRESS_FW_RESET_CTL_START, isp->base + + BUTTRESS_REG_FW_RESET_CTL); + + ret = readl_poll_timeout(isp->base + BUTTRESS_REG_FW_RESET_CTL, val, + val & BUTTRESS_FW_RESET_CTL_DONE, 500, + BUTTRESS_CSE_FWRESET_TIMEOUT_US); + if (ret) { + dev_err(dev, "Time out while resetting authentication state\n"); + return ret; + } + + dev_dbg(dev, "FW reset for authentication done\n"); + writel(0, isp->base + BUTTRESS_REG_FW_RESET_CTL); + /* leave some time for HW restore */ + usleep_range(800, 1000); + + return 0; +} + +int ipu_buttress_authenticate(struct ipu7_device *isp) +{ + struct ipu_buttress *b = &isp->buttress; + struct device *dev = &isp->pdev->dev; + u32 data, mask, done, fail; + int ret; + + if (!isp->secure_mode) { + dev_dbg(dev, "Skip auth for non-secure mode\n"); + return 0; + } + + mutex_lock(&b->auth_mutex); + + if (ipu_buttress_auth_done(isp)) { + ret = 0; + goto out_unlock; + } + + /* + * BUTTRESS_REG_FW_SOURCE_BASE needs to be set with FW CPD + * package address for secure mode. + */ + + writel(isp->cpd_fw->size, isp->base + BUTTRESS_REG_FW_SOURCE_SIZE); + writel(sg_dma_address(isp->psys->fw_sgt.sgl), + isp->base + BUTTRESS_REG_FW_SOURCE_BASE); + + /* + * Write boot_load into IU2CSEDATA0 + * Write sizeof(boot_load) | 0x2 << CLIENT_ID to + * IU2CSEDB.IU2CSECMD and set IU2CSEDB.IU2CSEBUSY as + */ + dev_info(dev, "Sending BOOT_LOAD to CSE\n"); + ret = ipu_buttress_ipc_send(isp, BUTTRESS_IU2CSEDATA0_IPC_BOOT_LOAD, + 1, true, + BUTTRESS_CSE2IUDATA0_IPC_BOOT_LOAD_DONE); + if (ret) { + dev_err(dev, "CSE boot_load failed\n"); + goto out_unlock; + } + + mask = BUTTRESS_SECURITY_CTL_FW_SETUP_MASK; + done = BUTTRESS_SECURITY_CTL_FW_SETUP_DONE; + fail = BUTTRESS_SECURITY_CTL_AUTH_FAILED; + ret = readl_poll_timeout(isp->base + BUTTRESS_REG_SECURITY_CTL, data, + ((data & mask) == done || + (data & mask) == fail), 500, + BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US); + if (ret) { + dev_err(dev, "CSE boot_load timeout\n"); + goto out_unlock; + } + + if ((data & mask) == fail) { + dev_err(dev, "CSE auth failed\n"); + ret = -EINVAL; + goto out_unlock; + } + + ret = readl_poll_timeout(isp->base + BOOTLOADER_STATUS_OFFSET, + data, data == BOOTLOADER_MAGIC_KEY, 500, + BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US); + if (ret) { + dev_err(dev, "Unexpected magic number 0x%x\n", data); + goto out_unlock; + } + + /* + * Write authenticate_run into IU2CSEDATA0 + * Write sizeof(boot_load) | 0x2 << CLIENT_ID to + * IU2CSEDB.IU2CSECMD and set IU2CSEDB.IU2CSEBUSY as + */ + dev_info(dev, "Sending AUTHENTICATE_RUN to CSE\n"); + ret = ipu_buttress_ipc_send(isp, BUTTRESS_IU2CSEDATA0_IPC_AUTH_RUN, + 1, true, + BUTTRESS_CSE2IUDATA0_IPC_AUTH_RUN_DONE); + if (ret) { + dev_err(dev, "CSE authenticate_run failed\n"); + goto out_unlock; + } + + done = BUTTRESS_SECURITY_CTL_AUTH_DONE; + ret = readl_poll_timeout(isp->base + BUTTRESS_REG_SECURITY_CTL, data, + ((data & mask) == done || + (data & mask) == fail), 500, + BUTTRESS_CSE_AUTHENTICATE_TIMEOUT_US); + if (ret) { + dev_err(dev, "CSE authenticate timeout\n"); + goto out_unlock; + } + + if ((data & mask) == fail) { + dev_err(dev, "CSE boot_load failed\n"); + ret = -EINVAL; + goto out_unlock; + } + + dev_info(dev, "CSE authenticate_run done\n"); + +out_unlock: + mutex_unlock(&b->auth_mutex); + + return ret; +} + +static int ipu_buttress_send_tsc_request(struct ipu7_device *isp) +{ + u32 val, mask, done; + int ret; + + mask = BUTTRESS_PWR_STATUS_HH_STATUS_MASK; + + writel(BUTTRESS_TSC_CMD_START_TSC_SYNC, + isp->base + BUTTRESS_REG_TSC_CMD); + + val = readl(isp->base + BUTTRESS_REG_PWR_STATUS); + val = FIELD_GET(mask, val); + if (val == BUTTRESS_PWR_STATUS_HH_STATE_ERR) { + dev_err(&isp->pdev->dev, "Start tsc sync failed\n"); + return -EINVAL; + } + + done = BUTTRESS_PWR_STATUS_HH_STATE_DONE; + ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATUS, val, + FIELD_GET(mask, val) == done, 500, + BUTTRESS_TSC_SYNC_TIMEOUT_US); + if (ret) + dev_err(&isp->pdev->dev, "Start tsc sync timeout\n"); + + return ret; +} + +int ipu_buttress_start_tsc_sync(struct ipu7_device *isp) +{ + void __iomem *base = isp->base; + unsigned int i; + u32 val; + + if (is_ipu8(isp->hw_ver)) { + for (i = 0; i < BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX; i++) { + val = readl(base + BUTTRESS_REG_PB_TIMESTAMP_VALID); + if (val == 1) + return 0; + usleep_range(40, 50); + } + + dev_err(&isp->pdev->dev, "PB HH sync failed (valid %u)\n", val); + return -ETIMEDOUT; + } + + if (is_ipu7p5(isp->hw_ver)) { + val = readl(base + BUTTRESS_REG_TSC_CTL); + val |= BUTTRESS_SEL_PB_TIMESTAMP; + writel(val, base + BUTTRESS_REG_TSC_CTL); + + for (i = 0; i < BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX; i++) { + val = readl(base + BUTTRESS_REG_PB_TIMESTAMP_VALID); + if (val == 1) + return 0; + usleep_range(40, 50); + } + + dev_err(&isp->pdev->dev, "PB HH sync failed (valid %u)\n", val); + + return -ETIMEDOUT; + } + + for (i = 0; i < BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX; i++) { + int ret; + + ret = ipu_buttress_send_tsc_request(isp); + if (ret != -ETIMEDOUT) + return ret; + + val = readl(base + BUTTRESS_REG_TSC_CTL); + val = val | BUTTRESS_TSW_WA_SOFT_RESET; + writel(val, base + BUTTRESS_REG_TSC_CTL); + val = val & (~BUTTRESS_TSW_WA_SOFT_RESET); + writel(val, base + BUTTRESS_REG_TSC_CTL); + } + + dev_err(&isp->pdev->dev, "TSC sync failed (timeout)\n"); + + return -ETIMEDOUT; +} +EXPORT_SYMBOL_NS_GPL(ipu_buttress_start_tsc_sync, "INTEL_IPU7"); + +void ipu_buttress_tsc_read(struct ipu7_device *isp, u64 *val) +{ + unsigned long flags; + u32 tsc_hi, tsc_lo; + + local_irq_save(flags); + if (is_ipu7(isp->hw_ver)) { + tsc_lo = readl(isp->base + BUTTRESS_REG_TSC_LO); + tsc_hi = readl(isp->base + BUTTRESS_REG_TSC_HI); + } else { + tsc_lo = readl(isp->base + BUTTRESS_REG_PB_TIMESTAMP_LO); + tsc_hi = readl(isp->base + BUTTRESS_REG_PB_TIMESTAMP_HI); + } + *val = (u64)tsc_hi << 32 | tsc_lo; + local_irq_restore(flags); +} +EXPORT_SYMBOL_NS_GPL(ipu_buttress_tsc_read, "INTEL_IPU7"); + +u64 ipu_buttress_tsc_ticks_to_ns(u64 ticks, const struct ipu7_device *isp) +{ + u64 ns = ticks * 10000; + + /* + * converting TSC tick count to ns is calculated by: + * Example (TSC clock frequency is 19.2MHz): + * ns = ticks * 1000 000 000 / 19.2Mhz + * = ticks * 1000 000 000 / 19200000Hz + * = ticks * 10000 / 192 ns + */ + return div_u64(ns, isp->buttress.ref_clk); +} +EXPORT_SYMBOL_NS_GPL(ipu_buttress_tsc_ticks_to_ns, "INTEL_IPU7"); + +/* trigger uc control to wakeup fw */ +void ipu_buttress_wakeup_is_uc(const struct ipu7_device *isp) +{ + u32 val; + + val = readl(isp->base + BUTTRESS_REG_DRV_IS_UCX_CONTROL_STATUS); + val |= UCX_CTL_WAKEUP; + writel(val, isp->base + BUTTRESS_REG_DRV_IS_UCX_CONTROL_STATUS); +} +EXPORT_SYMBOL_NS_GPL(ipu_buttress_wakeup_is_uc, "INTEL_IPU7"); + +void ipu_buttress_wakeup_ps_uc(const struct ipu7_device *isp) +{ + u32 val; + + val = readl(isp->base + BUTTRESS_REG_DRV_PS_UCX_CONTROL_STATUS); + val |= UCX_CTL_WAKEUP; + writel(val, isp->base + BUTTRESS_REG_DRV_PS_UCX_CONTROL_STATUS); +} +EXPORT_SYMBOL_NS_GPL(ipu_buttress_wakeup_ps_uc, "INTEL_IPU7"); + +static const struct x86_cpu_id ipu_misc_cfg_exclusion[] = { + X86_MATCH_VFM_STEPS(INTEL_PANTHERLAKE_L, 0x1, 0x1, 0), + {}, +}; + +static void ipu_buttress_setup(struct ipu7_device *isp) +{ + struct device *dev = &isp->pdev->dev; + u32 val; + + /* program PB BAR */ +#define WRXREQOP_OVRD_VAL_MASK GENMASK(22, 19) + writel(0, isp->pb_base + GLOBAL_INTERRUPT_MASK); + val = readl(isp->pb_base + BAR2_MISC_CONFIG); + if (is_ipu7(isp->hw_ver) || x86_match_cpu(ipu_misc_cfg_exclusion)) + val |= 0x100U; + else + val |= FIELD_PREP(WRXREQOP_OVRD_VAL_MASK, 0xf) | + BIT(18) | 0x100U; + + writel(val, isp->pb_base + BAR2_MISC_CONFIG); + val = readl(isp->pb_base + BAR2_MISC_CONFIG); + + if (is_ipu8(isp->hw_ver)) { + writel(BIT(13), isp->pb_base + TLBID_HASH_ENABLE_63_32); + writel(BIT(9), isp->pb_base + TLBID_HASH_ENABLE_95_64); + dev_dbg(dev, "IPU8 TLBID_HASH %x %x\n", + readl(isp->pb_base + TLBID_HASH_ENABLE_63_32), + readl(isp->pb_base + TLBID_HASH_ENABLE_95_64)); + } else if (is_ipu7p5(isp->hw_ver)) { + writel(BIT(14), isp->pb_base + TLBID_HASH_ENABLE_63_32); + writel(BIT(9), isp->pb_base + TLBID_HASH_ENABLE_95_64); + dev_dbg(dev, "IPU7P5 TLBID_HASH %x %x\n", + readl(isp->pb_base + TLBID_HASH_ENABLE_63_32), + readl(isp->pb_base + TLBID_HASH_ENABLE_95_64)); + } else { + writel(BIT(22), isp->pb_base + TLBID_HASH_ENABLE_63_32); + writel(BIT(1), isp->pb_base + TLBID_HASH_ENABLE_127_96); + dev_dbg(dev, "TLBID_HASH %x %x\n", + readl(isp->pb_base + TLBID_HASH_ENABLE_63_32), + readl(isp->pb_base + TLBID_HASH_ENABLE_127_96)); + } + + writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_IRQ_CLEAR); + writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_IRQ_MASK); + writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_IRQ_ENABLE); + /* LNL SW workaround for PS PD hang when PS sub-domain during PD */ + writel(PS_FSM_CG, isp->base + BUTTRESS_REG_CG_CTRL_BITS); +} + +void ipu_buttress_restore(struct ipu7_device *isp) +{ + struct ipu_buttress *b = &isp->buttress; + + ipu_buttress_setup(isp); + + writel(b->wdt_cached_value, isp->base + BUTTRESS_REG_IDLE_WDT); +} + +int ipu_buttress_init(struct ipu7_device *isp) +{ + int ret, ipc_reset_retry = BUTTRESS_CSE_IPC_RESET_RETRY; + struct ipu_buttress *b = &isp->buttress; + struct device *dev = &isp->pdev->dev; + u32 val; + + mutex_init(&b->power_mutex); + mutex_init(&b->auth_mutex); + mutex_init(&b->cons_mutex); + mutex_init(&b->ipc_mutex); + init_completion(&b->cse.send_complete); + init_completion(&b->cse.recv_complete); + + b->cse.nack = BUTTRESS_CSE2IUDATA0_IPC_NACK; + b->cse.nack_mask = BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK; + b->cse.csr_in = BUTTRESS_REG_CSE2IUCSR; + b->cse.csr_out = BUTTRESS_REG_IU2CSECSR; + b->cse.db0_in = BUTTRESS_REG_CSE2IUDB0; + b->cse.db0_out = BUTTRESS_REG_IU2CSEDB0; + b->cse.data0_in = BUTTRESS_REG_CSE2IUDATA0; + b->cse.data0_out = BUTTRESS_REG_IU2CSEDATA0; + + isp->secure_mode = ipu_buttress_get_secure_mode(isp); + val = readl(isp->base + BUTTRESS_REG_IPU_SKU); + dev_info(dev, "IPU%u SKU %u in %s mode mask 0x%x\n", val & 0xfU, + (val >> 4) & 0x7U, isp->secure_mode ? "secure" : "non-secure", + readl(isp->base + BUTTRESS_REG_CAMERA_MASK)); + b->wdt_cached_value = readl(isp->base + BUTTRESS_REG_IDLE_WDT); + b->ref_clk = 384; + + ipu_buttress_setup(isp); + + /* Retry couple of times in case of CSE initialization is delayed */ + do { + ret = ipu_buttress_ipc_reset(isp, &b->cse); + if (ret) { + dev_warn(dev, "IPC reset protocol failed, retrying\n"); + } else { + dev_dbg(dev, "IPC reset done\n"); + return 0; + } + } while (ipc_reset_retry--); + + dev_err(dev, "IPC reset protocol failed\n"); + + mutex_destroy(&b->power_mutex); + mutex_destroy(&b->auth_mutex); + mutex_destroy(&b->cons_mutex); + mutex_destroy(&b->ipc_mutex); + + return ret; +} + +void ipu_buttress_exit(struct ipu7_device *isp) +{ + struct ipu_buttress *b = &isp->buttress; + + writel(0, isp->base + BUTTRESS_REG_IRQ_ENABLE); + mutex_destroy(&b->power_mutex); + mutex_destroy(&b->auth_mutex); + mutex_destroy(&b->cons_mutex); + mutex_destroy(&b->ipc_mutex); +} diff --git a/drivers/staging/media/ipu7/ipu7-buttress.h b/drivers/staging/media/ipu7/ipu7-buttress.h new file mode 100644 index 0000000000000..8da7dd6125754 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-buttress.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#ifndef IPU7_BUTTRESS_H +#define IPU7_BUTTRESS_H + +#include <linux/completion.h> +#include <linux/irqreturn.h> +#include <linux/list.h> +#include <linux/mutex.h> + +struct device; +struct ipu7_device; + +struct ipu_buttress_ctrl { + u32 subsys_id; + u32 freq_ctl, pwr_sts_shift, pwr_sts_mask, pwr_sts_on, pwr_sts_off; + u32 ratio; + u32 ratio_shift; + u32 cdyn; + u32 cdyn_shift; + u32 ovrd_clk; + u32 own_clk_ack; +}; + +struct ipu_buttress_ipc { + struct completion send_complete; + struct completion recv_complete; + u32 nack; + u32 nack_mask; + u32 recv_data; + u32 csr_out; + u32 csr_in; + u32 db0_in; + u32 db0_out; + u32 data0_out; + u32 data0_in; +}; + +struct ipu_buttress { + struct mutex power_mutex, auth_mutex, cons_mutex, ipc_mutex; + struct ipu_buttress_ipc cse; + u32 psys_min_freq; + u32 wdt_cached_value; + u8 psys_force_ratio; + bool force_suspend; + u32 ref_clk; +}; + +int ipu_buttress_ipc_reset(struct ipu7_device *isp, + struct ipu_buttress_ipc *ipc); +int ipu_buttress_powerup(struct device *dev, + const struct ipu_buttress_ctrl *ctrl); +int ipu_buttress_powerdown(struct device *dev, + const struct ipu_buttress_ctrl *ctrl); +bool ipu_buttress_get_secure_mode(struct ipu7_device *isp); +int ipu_buttress_authenticate(struct ipu7_device *isp); +int ipu_buttress_reset_authentication(struct ipu7_device *isp); +bool ipu_buttress_auth_done(struct ipu7_device *isp); +int ipu_buttress_get_isys_freq(struct ipu7_device *isp, u32 *freq); +int ipu_buttress_get_psys_freq(struct ipu7_device *isp, u32 *freq); +int ipu_buttress_start_tsc_sync(struct ipu7_device *isp); +void ipu_buttress_tsc_read(struct ipu7_device *isp, u64 *val); +u64 ipu_buttress_tsc_ticks_to_ns(u64 ticks, const struct ipu7_device *isp); + +irqreturn_t ipu_buttress_isr(int irq, void *isp_ptr); +irqreturn_t ipu_buttress_isr_threaded(int irq, void *isp_ptr); +int ipu_buttress_init(struct ipu7_device *isp); +void ipu_buttress_exit(struct ipu7_device *isp); +void ipu_buttress_csi_port_config(struct ipu7_device *isp, + u32 legacy, u32 combo); +void ipu_buttress_restore(struct ipu7_device *isp); +void ipu_buttress_wakeup_is_uc(const struct ipu7_device *isp); +void ipu_buttress_wakeup_ps_uc(const struct ipu7_device *isp); +#endif /* IPU7_BUTTRESS_H */ diff --git a/drivers/staging/media/ipu7/ipu7-cpd.c b/drivers/staging/media/ipu7/ipu7-cpd.c new file mode 100644 index 0000000000000..4f49fb57eae44 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-cpd.c @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2015 - 2025 Intel Corporation + */ + +#include <linux/device.h> +#include <linux/export.h> +#include <linux/gfp_types.h> +#include <linux/pci.h> +#include <linux/sizes.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include "ipu7.h" +#include "ipu7-cpd.h" + +/* $CPD */ +#define CPD_HDR_MARK 0x44504324 + +/* Maximum size is 4K DWORDs or 16KB */ +#define MAX_MANIFEST_SIZE (SZ_4K * sizeof(u32)) + +#define CPD_MANIFEST_IDX 0 +#define CPD_BINARY_START_IDX 1U +#define CPD_METADATA_START_IDX 2U +#define CPD_BINARY_NUM 2U /* ISYS + PSYS */ +/* + * Entries include: + * 1 manifest entry. + * 1 metadata entry for each sub system(ISYS and PSYS). + * 1 binary entry for each sub system(ISYS and PSYS). + */ +#define CPD_ENTRY_NUM (CPD_BINARY_NUM * 2U + 1U) + +#define CPD_METADATA_ATTR 0xa +#define CPD_METADATA_IPL 0x1c +#define ONLINE_METADATA_SIZE 128U +#define ONLINE_METADATA_LINES 6U + +struct ipu7_cpd_hdr { + u32 hdr_mark; + u32 ent_cnt; + u8 hdr_ver; + u8 ent_ver; + u8 hdr_len; + u8 rsvd; + u8 partition_name[4]; + u32 crc32; +} __packed; + +struct ipu7_cpd_ent { + u8 name[12]; + u32 offset; + u32 len; + u8 rsvd[4]; +} __packed; + +struct ipu7_cpd_metadata_hdr { + u32 type; + u32 len; +} __packed; + +struct ipu7_cpd_metadata_attr { + struct ipu7_cpd_metadata_hdr hdr; + u8 compression_type; + u8 encryption_type; + u8 rsvd[2]; + u32 uncompressed_size; + u32 compressed_size; + u32 module_id; + u8 hash[48]; +} __packed; + +struct ipu7_cpd_metadata_ipl { + struct ipu7_cpd_metadata_hdr hdr; + u32 param[4]; + u8 rsvd[8]; +} __packed; + +struct ipu7_cpd_metadata { + struct ipu7_cpd_metadata_attr attr; + struct ipu7_cpd_metadata_ipl ipl; +} __packed; + +static inline struct ipu7_cpd_ent *ipu7_cpd_get_entry(const void *cpd, int idx) +{ + const struct ipu7_cpd_hdr *cpd_hdr = cpd; + + return ((struct ipu7_cpd_ent *)((u8 *)cpd + cpd_hdr->hdr_len)) + idx; +} + +#define ipu7_cpd_get_manifest(cpd) ipu7_cpd_get_entry(cpd, 0) + +static struct ipu7_cpd_metadata *ipu7_cpd_get_metadata(const void *cpd, int idx) +{ + struct ipu7_cpd_ent *cpd_ent = + ipu7_cpd_get_entry(cpd, CPD_METADATA_START_IDX + idx * 2); + + return (struct ipu7_cpd_metadata *)((u8 *)cpd + cpd_ent->offset); +} + +static int ipu7_cpd_validate_cpd(struct ipu7_device *isp, + const void *cpd, unsigned long data_size) +{ + const struct ipu7_cpd_hdr *cpd_hdr = cpd; + struct device *dev = &isp->pdev->dev; + struct ipu7_cpd_ent *ent; + unsigned int i; + u8 len; + + len = cpd_hdr->hdr_len; + + /* Ensure cpd hdr is within moduledata */ + if (data_size < len) { + dev_err(dev, "Invalid CPD moduledata size\n"); + return -EINVAL; + } + + /* Check for CPD file marker */ + if (cpd_hdr->hdr_mark != CPD_HDR_MARK) { + dev_err(dev, "Invalid CPD header marker\n"); + return -EINVAL; + } + + /* Sanity check for CPD entry header */ + if (cpd_hdr->ent_cnt != CPD_ENTRY_NUM) { + dev_err(dev, "Invalid CPD entry number %d\n", + cpd_hdr->ent_cnt); + return -EINVAL; + } + if ((data_size - len) / sizeof(*ent) < cpd_hdr->ent_cnt) { + dev_err(dev, "Invalid CPD entry headers\n"); + return -EINVAL; + } + + /* Ensure that all entries are within moduledata */ + ent = (struct ipu7_cpd_ent *)(((u8 *)cpd_hdr) + len); + for (i = 0; i < cpd_hdr->ent_cnt; i++) { + if (data_size < ent->offset || + data_size - ent->offset < ent->len) { + dev_err(dev, "Invalid CPD entry %d\n", i); + return -EINVAL; + } + ent++; + } + + return 0; +} + +static int ipu7_cpd_validate_metadata(struct ipu7_device *isp, + const void *cpd, int idx) +{ + const struct ipu7_cpd_ent *cpd_ent = + ipu7_cpd_get_entry(cpd, CPD_METADATA_START_IDX + idx * 2); + const struct ipu7_cpd_metadata *metadata = + ipu7_cpd_get_metadata(cpd, idx); + struct device *dev = &isp->pdev->dev; + + /* Sanity check for metadata size */ + if (cpd_ent->len != sizeof(struct ipu7_cpd_metadata)) { + dev_err(dev, "Invalid metadata size\n"); + return -EINVAL; + } + + /* Validate type and length of metadata sections */ + if (metadata->attr.hdr.type != CPD_METADATA_ATTR) { + dev_err(dev, "Invalid metadata attr type (%d)\n", + metadata->attr.hdr.type); + return -EINVAL; + } + if (metadata->attr.hdr.len != sizeof(struct ipu7_cpd_metadata_attr)) { + dev_err(dev, "Invalid metadata attr size (%d)\n", + metadata->attr.hdr.len); + return -EINVAL; + } + if (metadata->ipl.hdr.type != CPD_METADATA_IPL) { + dev_err(dev, "Invalid metadata ipl type (%d)\n", + metadata->ipl.hdr.type); + return -EINVAL; + } + if (metadata->ipl.hdr.len != sizeof(struct ipu7_cpd_metadata_ipl)) { + dev_err(dev, "Invalid metadata ipl size (%d)\n", + metadata->ipl.hdr.len); + return -EINVAL; + } + + return 0; +} + +int ipu7_cpd_validate_cpd_file(struct ipu7_device *isp, const void *cpd_file, + unsigned long cpd_file_size) +{ + struct device *dev = &isp->pdev->dev; + struct ipu7_cpd_ent *ent; + unsigned int i; + int ret; + char *buf; + + ret = ipu7_cpd_validate_cpd(isp, cpd_file, cpd_file_size); + if (ret) { + dev_err(dev, "Invalid CPD in file\n"); + return -EINVAL; + } + + /* Sanity check for manifest size */ + ent = ipu7_cpd_get_manifest(cpd_file); + if (ent->len > MAX_MANIFEST_SIZE) { + dev_err(dev, "Invalid manifest size\n"); + return -EINVAL; + } + + /* Validate metadata */ + for (i = 0; i < CPD_BINARY_NUM; i++) { + ret = ipu7_cpd_validate_metadata(isp, cpd_file, i); + if (ret) { + dev_err(dev, "Invalid metadata%d\n", i); + return ret; + } + } + + /* Get fw binary version. */ + buf = kmalloc(ONLINE_METADATA_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + for (i = 0; i < CPD_BINARY_NUM; i++) { + char *lines[ONLINE_METADATA_LINES]; + char *info = buf; + unsigned int l; + + ent = ipu7_cpd_get_entry(cpd_file, + CPD_BINARY_START_IDX + i * 2U); + memcpy(info, (u8 *)cpd_file + ent->offset + ent->len - + ONLINE_METADATA_SIZE, ONLINE_METADATA_SIZE); + for (l = 0; l < ONLINE_METADATA_LINES; l++) { + lines[l] = strsep((char **)&info, "\n"); + if (!lines[l]) + break; + } + if (l < ONLINE_METADATA_LINES) { + dev_err(dev, "Failed to parse fw binary%d info.\n", i); + continue; + } + dev_info(dev, "FW binary%d info:\n", i); + dev_info(dev, "Name: %s\n", lines[1]); + dev_info(dev, "Version: %s\n", lines[2]); + dev_info(dev, "Timestamp: %s\n", lines[3]); + dev_info(dev, "Commit: %s\n", lines[4]); + } + kfree(buf); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ipu7_cpd_validate_cpd_file, "INTEL_IPU7"); + +int ipu7_cpd_copy_binary(const void *cpd, const char *name, + void *code_region, u32 *entry) +{ + unsigned int i; + + for (i = 0; i < CPD_BINARY_NUM; i++) { + const struct ipu7_cpd_ent *binary = + ipu7_cpd_get_entry(cpd, CPD_BINARY_START_IDX + i * 2U); + const struct ipu7_cpd_metadata *metadata = + ipu7_cpd_get_metadata(cpd, i); + + if (!strncmp(binary->name, name, sizeof(binary->name))) { + memcpy(code_region + metadata->ipl.param[0], + cpd + binary->offset, binary->len); + *entry = metadata->ipl.param[2]; + return 0; + } + } + + return -ENOENT; +} +EXPORT_SYMBOL_NS_GPL(ipu7_cpd_copy_binary, "INTEL_IPU7"); diff --git a/drivers/staging/media/ipu7/ipu7-cpd.h b/drivers/staging/media/ipu7/ipu7-cpd.h new file mode 100644 index 0000000000000..b4178848c6b94 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-cpd.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2015 - 2025 Intel Corporation + */ + +#ifndef IPU7_CPD_H +#define IPU7_CPD_H + +struct ipu7_device; + +int ipu7_cpd_validate_cpd_file(struct ipu7_device *isp, + const void *cpd_file, + unsigned long cpd_file_size); +int ipu7_cpd_copy_binary(const void *cpd, const char *name, + void *code_region, u32 *entry); +#endif /* IPU7_CPD_H */ diff --git a/drivers/staging/media/ipu7/ipu7-dma.c b/drivers/staging/media/ipu7/ipu7-dma.c new file mode 100644 index 0000000000000..a118b41b2f34e --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-dma.c @@ -0,0 +1,477 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <linux/cacheflush.h> +#include <linux/dma-mapping.h> +#include <linux/iova.h> +#include <linux/list.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include "ipu7.h" +#include "ipu7-bus.h" +#include "ipu7-dma.h" +#include "ipu7-mmu.h" + +struct vm_info { + struct list_head list; + struct page **pages; + dma_addr_t ipu7_iova; + void *vaddr; + unsigned long size; +}; + +static struct vm_info *get_vm_info(struct ipu7_mmu *mmu, dma_addr_t iova) +{ + struct vm_info *info, *save; + + list_for_each_entry_safe(info, save, &mmu->vma_list, list) { + if (iova >= info->ipu7_iova && + iova < (info->ipu7_iova + info->size)) + return info; + } + + return NULL; +} + +static void __clear_buffer(struct page *page, size_t size, unsigned long attrs) +{ + void *ptr; + + if (!page) + return; + /* + * Ensure that the allocated pages are zeroed, and that any data + * lurking in the kernel direct-mapped region is invalidated. + */ + ptr = page_address(page); + memset(ptr, 0, size); + if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0) + clflush_cache_range(ptr, size); +} + +static struct page **__alloc_buffer(size_t size, gfp_t gfp, unsigned long attrs) +{ + unsigned int count = PHYS_PFN(size); + unsigned int array_size = count * sizeof(struct page *); + struct page **pages; + int i = 0; + + pages = kvzalloc(array_size, GFP_KERNEL); + if (!pages) + return NULL; + + gfp |= __GFP_NOWARN; + + while (count) { + int j, order = __fls(count); + + pages[i] = alloc_pages(gfp, order); + while (!pages[i] && order) + pages[i] = alloc_pages(gfp, --order); + if (!pages[i]) + goto error; + + if (order) { + split_page(pages[i], order); + j = 1U << order; + while (j--) + pages[i + j] = pages[i] + j; + } + + __clear_buffer(pages[i], PAGE_SIZE << order, attrs); + i += 1U << order; + count -= 1U << order; + } + + return pages; +error: + while (i--) + if (pages[i]) + __free_pages(pages[i], 0); + kvfree(pages); + return NULL; +} + +static void __free_buffer(struct page **pages, size_t size, unsigned long attrs) +{ + unsigned int count = PHYS_PFN(size); + unsigned int i; + + for (i = 0; i < count && pages[i]; i++) { + __clear_buffer(pages[i], PAGE_SIZE, attrs); + __free_pages(pages[i], 0); + } + + kvfree(pages); +} + +void ipu7_dma_sync_single(struct ipu7_bus_device *sys, dma_addr_t dma_handle, + size_t size) +{ + void *vaddr; + u32 offset; + struct vm_info *info; + struct ipu7_mmu *mmu = sys->mmu; + + info = get_vm_info(mmu, dma_handle); + if (WARN_ON(!info)) + return; + + offset = dma_handle - info->ipu7_iova; + if (WARN_ON(size > (info->size - offset))) + return; + + vaddr = info->vaddr + offset; + clflush_cache_range(vaddr, size); +} +EXPORT_SYMBOL_NS_GPL(ipu7_dma_sync_single, "INTEL_IPU7"); + +void ipu7_dma_sync_sg(struct ipu7_bus_device *sys, struct scatterlist *sglist, + unsigned int nents) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sglist, sg, nents, i) + clflush_cache_range(sg_virt(sg), sg->length); +} +EXPORT_SYMBOL_NS_GPL(ipu7_dma_sync_sg, "INTEL_IPU7"); + +void ipu7_dma_sync_sgtable(struct ipu7_bus_device *sys, struct sg_table *sgt) +{ + ipu7_dma_sync_sg(sys, sgt->sgl, sgt->orig_nents); +} +EXPORT_SYMBOL_NS_GPL(ipu7_dma_sync_sgtable, "INTEL_IPU7"); + +void *ipu7_dma_alloc(struct ipu7_bus_device *sys, size_t size, + dma_addr_t *dma_handle, gfp_t gfp, + unsigned long attrs) +{ + struct device *dev = &sys->auxdev.dev; + struct pci_dev *pdev = sys->isp->pdev; + dma_addr_t pci_dma_addr, ipu7_iova; + struct ipu7_mmu *mmu = sys->mmu; + struct vm_info *info; + unsigned long count; + struct page **pages; + struct iova *iova; + unsigned int i; + int ret; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + + size = PAGE_ALIGN(size); + count = PHYS_PFN(size); + + iova = alloc_iova(&mmu->dmap->iovad, count, + PHYS_PFN(mmu->dmap->mmu_info->aperture_end), 0); + if (!iova) + goto out_kfree; + + pages = __alloc_buffer(size, gfp, attrs); + if (!pages) + goto out_free_iova; + + dev_dbg(dev, "dma_alloc: size %zu iova low pfn %lu, high pfn %lu\n", + size, iova->pfn_lo, iova->pfn_hi); + for (i = 0; iova->pfn_lo + i <= iova->pfn_hi; i++) { + pci_dma_addr = dma_map_page_attrs(&pdev->dev, pages[i], 0, + PAGE_SIZE, DMA_BIDIRECTIONAL, + attrs); + dev_dbg(dev, "dma_alloc: mapped pci_dma_addr %pad\n", + &pci_dma_addr); + if (dma_mapping_error(&pdev->dev, pci_dma_addr)) { + dev_err(dev, "pci_dma_mapping for page[%d] failed", i); + goto out_unmap; + } + + ret = ipu7_mmu_map(mmu->dmap->mmu_info, + PFN_PHYS(iova->pfn_lo + i), pci_dma_addr, + PAGE_SIZE); + if (ret) { + dev_err(dev, "ipu7_mmu_map for pci_dma[%d] %pad failed", + i, &pci_dma_addr); + dma_unmap_page_attrs(&pdev->dev, pci_dma_addr, + PAGE_SIZE, DMA_BIDIRECTIONAL, + attrs); + goto out_unmap; + } + } + + info->vaddr = vmap(pages, count, VM_USERMAP, PAGE_KERNEL); + if (!info->vaddr) + goto out_unmap; + + *dma_handle = PFN_PHYS(iova->pfn_lo); + + info->pages = pages; + info->ipu7_iova = *dma_handle; + info->size = size; + list_add(&info->list, &mmu->vma_list); + + return info->vaddr; + +out_unmap: + while (i--) { + ipu7_iova = PFN_PHYS(iova->pfn_lo + i); + pci_dma_addr = ipu7_mmu_iova_to_phys(mmu->dmap->mmu_info, + ipu7_iova); + dma_unmap_page_attrs(&pdev->dev, pci_dma_addr, PAGE_SIZE, + DMA_BIDIRECTIONAL, attrs); + + ipu7_mmu_unmap(mmu->dmap->mmu_info, ipu7_iova, PAGE_SIZE); + } + + __free_buffer(pages, size, attrs); + +out_free_iova: + __free_iova(&mmu->dmap->iovad, iova); +out_kfree: + kfree(info); + + return NULL; +} +EXPORT_SYMBOL_NS_GPL(ipu7_dma_alloc, "INTEL_IPU7"); + +void ipu7_dma_free(struct ipu7_bus_device *sys, size_t size, void *vaddr, + dma_addr_t dma_handle, unsigned long attrs) +{ + struct ipu7_mmu *mmu = sys->mmu; + struct pci_dev *pdev = sys->isp->pdev; + struct iova *iova = find_iova(&mmu->dmap->iovad, PHYS_PFN(dma_handle)); + dma_addr_t pci_dma_addr, ipu7_iova; + struct vm_info *info; + struct page **pages; + unsigned int i; + + if (WARN_ON(!iova)) + return; + + info = get_vm_info(mmu, dma_handle); + if (WARN_ON(!info)) + return; + + if (WARN_ON(!info->vaddr)) + return; + + if (WARN_ON(!info->pages)) + return; + + list_del(&info->list); + + size = PAGE_ALIGN(size); + + pages = info->pages; + + vunmap(vaddr); + + for (i = 0; i < PHYS_PFN(size); i++) { + ipu7_iova = PFN_PHYS(iova->pfn_lo + i); + pci_dma_addr = ipu7_mmu_iova_to_phys(mmu->dmap->mmu_info, + ipu7_iova); + dma_unmap_page_attrs(&pdev->dev, pci_dma_addr, PAGE_SIZE, + DMA_BIDIRECTIONAL, attrs); + } + + ipu7_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo), + PFN_PHYS(iova_size(iova))); + + __free_buffer(pages, size, attrs); + + mmu->tlb_invalidate(mmu); + + __free_iova(&mmu->dmap->iovad, iova); + + kfree(info); +} +EXPORT_SYMBOL_NS_GPL(ipu7_dma_free, "INTEL_IPU7"); + +int ipu7_dma_mmap(struct ipu7_bus_device *sys, struct vm_area_struct *vma, + void *addr, dma_addr_t iova, size_t size, + unsigned long attrs) +{ + struct ipu7_mmu *mmu = sys->mmu; + size_t count = PFN_UP(size); + struct vm_info *info; + size_t i; + int ret; + + info = get_vm_info(mmu, iova); + if (!info) + return -EFAULT; + + if (!info->vaddr) + return -EFAULT; + + if (vma->vm_start & ~PAGE_MASK) + return -EINVAL; + + if (size > info->size) + return -EFAULT; + + for (i = 0; i < count; i++) { + ret = vm_insert_page(vma, vma->vm_start + PFN_PHYS(i), + info->pages[i]); + if (ret < 0) + return ret; + } + + return 0; +} + +void ipu7_dma_unmap_sg(struct ipu7_bus_device *sys, struct scatterlist *sglist, + int nents, enum dma_data_direction dir, + unsigned long attrs) +{ + struct device *dev = &sys->auxdev.dev; + struct ipu7_mmu *mmu = sys->mmu; + struct iova *iova = find_iova(&mmu->dmap->iovad, + PHYS_PFN(sg_dma_address(sglist))); + struct scatterlist *sg; + dma_addr_t pci_dma_addr; + unsigned int i; + + if (!nents) + return; + + if (WARN_ON(!iova)) + return; + + /* + * Before IPU7 mmu unmap, return the pci dma address back to sg + * assume the nents is less than orig_nents as the least granule + * is 1 SZ_4K page + */ + dev_dbg(dev, "trying to unmap concatenated %u ents\n", nents); + for_each_sg(sglist, sg, nents, i) { + dev_dbg(dev, "unmap sg[%d] %pad size %u\n", i, + &sg_dma_address(sg), sg_dma_len(sg)); + pci_dma_addr = ipu7_mmu_iova_to_phys(mmu->dmap->mmu_info, + sg_dma_address(sg)); + dev_dbg(dev, "return pci_dma_addr %pad back to sg[%d]\n", + &pci_dma_addr, i); + sg_dma_address(sg) = pci_dma_addr; + } + + dev_dbg(dev, "ipu7_mmu_unmap low pfn %lu high pfn %lu\n", + iova->pfn_lo, iova->pfn_hi); + ipu7_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo), + PFN_PHYS(iova_size(iova))); + + mmu->tlb_invalidate(mmu); + __free_iova(&mmu->dmap->iovad, iova); +} +EXPORT_SYMBOL_NS_GPL(ipu7_dma_unmap_sg, "INTEL_IPU7"); + +int ipu7_dma_map_sg(struct ipu7_bus_device *sys, struct scatterlist *sglist, + int nents, enum dma_data_direction dir, + unsigned long attrs) +{ + struct device *dev = &sys->auxdev.dev; + struct ipu7_mmu *mmu = sys->mmu; + struct scatterlist *sg; + struct iova *iova; + size_t npages = 0; + unsigned long iova_addr; + int i; + + for_each_sg(sglist, sg, nents, i) { + if (sg->offset) { + dev_err(dev, "Unsupported non-zero sg[%d].offset %x\n", + i, sg->offset); + return -EFAULT; + } + } + + for_each_sg(sglist, sg, nents, i) + npages += PFN_UP(sg_dma_len(sg)); + + dev_dbg(dev, "dmamap trying to map %d ents %zu pages\n", + nents, npages); + + if (attrs & DMA_ATTR_RESERVE_REGION) { + /* + * Reserve iova with size aligned to IPU_FW_CODE_REGION_SIZE. + * Only apply for non-secure mode. + */ + unsigned long lo, hi; + + lo = iova_pfn(&mmu->dmap->iovad, IPU_FW_CODE_REGION_START); + hi = iova_pfn(&mmu->dmap->iovad, IPU_FW_CODE_REGION_END) - 1U; + iova = reserve_iova(&mmu->dmap->iovad, lo, hi); + if (!iova) { + dev_err(dev, "Reserve iova[%lx:%lx] failed.\n", lo, hi); + return -ENOMEM; + } + dev_dbg(dev, "iova[%lx:%lx] reserved for FW code.\n", lo, hi); + } else { + iova = alloc_iova(&mmu->dmap->iovad, npages, + PHYS_PFN(mmu->dmap->mmu_info->aperture_end), + 0); + if (!iova) + return 0; + } + + dev_dbg(dev, "dmamap: iova low pfn %lu, high pfn %lu\n", iova->pfn_lo, + iova->pfn_hi); + + iova_addr = iova->pfn_lo; + for_each_sg(sglist, sg, nents, i) { + phys_addr_t iova_pa; + int ret; + + iova_pa = PFN_PHYS(iova_addr); + dev_dbg(dev, "mapping entry %d: iova %pap phy %pap size %d\n", + i, &iova_pa, &sg_dma_address(sg), sg_dma_len(sg)); + + ret = ipu7_mmu_map(mmu->dmap->mmu_info, PFN_PHYS(iova_addr), + sg_dma_address(sg), + PAGE_ALIGN(sg_dma_len(sg))); + if (ret) + goto out_fail; + + sg_dma_address(sg) = PFN_PHYS(iova_addr); + + iova_addr += PFN_UP(sg_dma_len(sg)); + } + + dev_dbg(dev, "dmamap %d ents %zu pages mapped\n", nents, npages); + + return nents; + +out_fail: + ipu7_dma_unmap_sg(sys, sglist, i, dir, attrs); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ipu7_dma_map_sg, "INTEL_IPU7"); + +int ipu7_dma_map_sgtable(struct ipu7_bus_device *sys, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs) +{ + int nents; + + nents = ipu7_dma_map_sg(sys, sgt->sgl, sgt->nents, dir, attrs); + if (nents < 0) + return nents; + + sgt->nents = nents; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ipu7_dma_map_sgtable, "INTEL_IPU7"); + +void ipu7_dma_unmap_sgtable(struct ipu7_bus_device *sys, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs) +{ + ipu7_dma_unmap_sg(sys, sgt->sgl, sgt->nents, dir, attrs); +} +EXPORT_SYMBOL_NS_GPL(ipu7_dma_unmap_sgtable, "INTEL_IPU7"); diff --git a/drivers/staging/media/ipu7/ipu7-dma.h b/drivers/staging/media/ipu7/ipu7-dma.h new file mode 100644 index 0000000000000..fe789af5e664b --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-dma.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2013--2025 Intel Corporation */ + +#ifndef IPU7_DMA_H +#define IPU7_DMA_H + +#include <linux/dma-map-ops.h> +#include <linux/dma-mapping.h> +#include <linux/iova.h> +#include <linux/scatterlist.h> +#include <linux/types.h> + +#include "ipu7-bus.h" + +#define DMA_ATTR_RESERVE_REGION BIT(31) +struct ipu7_mmu_info; + +struct ipu7_dma_mapping { + struct ipu7_mmu_info *mmu_info; + struct iova_domain iovad; +}; + +void ipu7_dma_sync_single(struct ipu7_bus_device *sys, dma_addr_t dma_handle, + size_t size); +void ipu7_dma_sync_sg(struct ipu7_bus_device *sys, struct scatterlist *sglist, + unsigned int nents); +void ipu7_dma_sync_sgtable(struct ipu7_bus_device *sys, struct sg_table *sgt); +void *ipu7_dma_alloc(struct ipu7_bus_device *sys, size_t size, + dma_addr_t *dma_handle, gfp_t gfp, + unsigned long attrs); +void ipu7_dma_free(struct ipu7_bus_device *sys, size_t size, void *vaddr, + dma_addr_t dma_handle, unsigned long attrs); +int ipu7_dma_mmap(struct ipu7_bus_device *sys, struct vm_area_struct *vma, + void *addr, dma_addr_t iova, size_t size, + unsigned long attrs); +int ipu7_dma_map_sg(struct ipu7_bus_device *sys, struct scatterlist *sglist, + int nents, enum dma_data_direction dir, + unsigned long attrs); +void ipu7_dma_unmap_sg(struct ipu7_bus_device *sys, struct scatterlist *sglist, + int nents, enum dma_data_direction dir, + unsigned long attrs); +int ipu7_dma_map_sgtable(struct ipu7_bus_device *sys, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs); +void ipu7_dma_unmap_sgtable(struct ipu7_bus_device *sys, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs); +#endif /* IPU7_DMA_H */ diff --git a/drivers/staging/media/ipu7/ipu7-fw-isys.c b/drivers/staging/media/ipu7/ipu7-fw-isys.c new file mode 100644 index 0000000000000..e4b9c364572b9 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-fw-isys.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <linux/cacheflush.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/types.h> + +#include "abi/ipu7_fw_insys_config_abi.h" +#include "abi/ipu7_fw_isys_abi.h" + +#include "ipu7.h" +#include "ipu7-boot.h" +#include "ipu7-bus.h" +#include "ipu7-dma.h" +#include "ipu7-fw-isys.h" +#include "ipu7-isys.h" +#include "ipu7-platform-regs.h" +#include "ipu7-syscom.h" + +static const char * const send_msg_types[N_IPU_INSYS_SEND_TYPE] = { + "STREAM_OPEN", + "STREAM_START_AND_CAPTURE", + "STREAM_CAPTURE", + "STREAM_ABORT", + "STREAM_FLUSH", + "STREAM_CLOSE" +}; + +int ipu7_fw_isys_complex_cmd(struct ipu7_isys *isys, + const unsigned int stream_handle, + void *cpu_mapped_buf, + dma_addr_t dma_mapped_buf, + size_t size, u16 send_type) +{ + struct ipu7_syscom_context *ctx = isys->adev->syscom; + struct device *dev = &isys->adev->auxdev.dev; + struct ipu7_insys_send_queue_token *token; + + if (send_type >= N_IPU_INSYS_SEND_TYPE) + return -EINVAL; + + dev_dbg(dev, "send_token: %s\n", send_msg_types[send_type]); + + /* + * Time to flush cache in case we have some payload. Not all messages + * have that + */ + if (cpu_mapped_buf) + clflush_cache_range(cpu_mapped_buf, size); + + token = ipu7_syscom_get_token(ctx, stream_handle + + IPU_INSYS_INPUT_MSG_QUEUE); + if (!token) + return -EBUSY; + + token->addr = dma_mapped_buf; + token->buf_handle = (unsigned long)cpu_mapped_buf; + token->send_type = send_type; + token->stream_id = stream_handle; + token->flag = IPU_INSYS_SEND_QUEUE_TOKEN_FLAG_NONE; + + ipu7_syscom_put_token(ctx, stream_handle + IPU_INSYS_INPUT_MSG_QUEUE); + /* now wakeup FW */ + ipu_buttress_wakeup_is_uc(isys->adev->isp); + + return 0; +} + +int ipu7_fw_isys_simple_cmd(struct ipu7_isys *isys, + const unsigned int stream_handle, u16 send_type) +{ + return ipu7_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0, + send_type); +} + +int ipu7_fw_isys_init(struct ipu7_isys *isys) +{ + struct syscom_queue_config *queue_configs; + struct ipu7_bus_device *adev = isys->adev; + struct device *dev = &adev->auxdev.dev; + struct ipu7_insys_config *isys_config; + struct ipu7_syscom_context *syscom; + dma_addr_t isys_config_dma_addr; + unsigned int i, num_queues; + u32 freq; + u8 major; + int ret; + + /* Allocate and init syscom context. */ + syscom = devm_kzalloc(dev, sizeof(struct ipu7_syscom_context), + GFP_KERNEL); + if (!syscom) + return -ENOMEM; + + adev->syscom = syscom; + syscom->num_input_queues = IPU_INSYS_MAX_INPUT_QUEUES; + syscom->num_output_queues = IPU_INSYS_MAX_OUTPUT_QUEUES; + num_queues = syscom->num_input_queues + syscom->num_output_queues; + queue_configs = devm_kzalloc(dev, FW_QUEUE_CONFIG_SIZE(num_queues), + GFP_KERNEL); + if (!queue_configs) { + ipu7_fw_isys_release(isys); + return -ENOMEM; + } + syscom->queue_configs = queue_configs; + queue_configs[IPU_INSYS_OUTPUT_MSG_QUEUE].max_capacity = + IPU_ISYS_SIZE_RECV_QUEUE; + queue_configs[IPU_INSYS_OUTPUT_MSG_QUEUE].token_size_in_bytes = + sizeof(struct ipu7_insys_resp); + queue_configs[IPU_INSYS_OUTPUT_LOG_QUEUE].max_capacity = + IPU_ISYS_SIZE_LOG_QUEUE; + queue_configs[IPU_INSYS_OUTPUT_LOG_QUEUE].token_size_in_bytes = + sizeof(struct ipu7_insys_resp); + queue_configs[IPU_INSYS_OUTPUT_RESERVED_QUEUE].max_capacity = 0; + queue_configs[IPU_INSYS_OUTPUT_RESERVED_QUEUE].token_size_in_bytes = 0; + + queue_configs[IPU_INSYS_INPUT_DEV_QUEUE].max_capacity = + IPU_ISYS_MAX_STREAMS; + queue_configs[IPU_INSYS_INPUT_DEV_QUEUE].token_size_in_bytes = + sizeof(struct ipu7_insys_send_queue_token); + + for (i = IPU_INSYS_INPUT_MSG_QUEUE; i < num_queues; i++) { + queue_configs[i].max_capacity = IPU_ISYS_SIZE_SEND_QUEUE; + queue_configs[i].token_size_in_bytes = + sizeof(struct ipu7_insys_send_queue_token); + } + + /* Allocate ISYS subsys config. */ + isys_config = ipu7_dma_alloc(adev, sizeof(struct ipu7_insys_config), + &isys_config_dma_addr, GFP_KERNEL, 0); + if (!isys_config) { + dev_err(dev, "Failed to allocate isys subsys config.\n"); + ipu7_fw_isys_release(isys); + return -ENOMEM; + } + isys->subsys_config = isys_config; + isys->subsys_config_dma_addr = isys_config_dma_addr; + memset(isys_config, 0, sizeof(struct ipu7_insys_config)); + isys_config->logger_config.use_source_severity = 0; + isys_config->logger_config.use_channels_enable_bitmask = 1; + isys_config->logger_config.channels_enable_bitmask = + LOGGER_CONFIG_CHANNEL_ENABLE_SYSCOM_BITMASK; + isys_config->logger_config.hw_printf_buffer_base_addr = 0U; + isys_config->logger_config.hw_printf_buffer_size_bytes = 0U; + isys_config->wdt_config.wdt_timer1_us = 0; + isys_config->wdt_config.wdt_timer2_us = 0; + ret = ipu_buttress_get_isys_freq(adev->isp, &freq); + if (ret) { + dev_err(dev, "Failed to get ISYS frequency.\n"); + ipu7_fw_isys_release(isys); + return ret; + } + + ipu7_dma_sync_single(adev, isys_config_dma_addr, + sizeof(struct ipu7_insys_config)); + + major = is_ipu8(adev->isp->hw_ver) ? 2U : 1U; + ret = ipu7_boot_init_boot_config(adev, queue_configs, num_queues, + freq, isys_config_dma_addr, major); + if (ret) + ipu7_fw_isys_release(isys); + + return ret; +} + +void ipu7_fw_isys_release(struct ipu7_isys *isys) +{ + struct ipu7_bus_device *adev = isys->adev; + + ipu7_boot_release_boot_config(adev); + if (isys->subsys_config) { + ipu7_dma_free(adev, + sizeof(struct ipu7_insys_config), + isys->subsys_config, + isys->subsys_config_dma_addr, 0); + isys->subsys_config = NULL; + isys->subsys_config_dma_addr = 0; + } +} + +int ipu7_fw_isys_open(struct ipu7_isys *isys) +{ + return ipu7_boot_start_fw(isys->adev); +} + +int ipu7_fw_isys_close(struct ipu7_isys *isys) +{ + return ipu7_boot_stop_fw(isys->adev); +} + +struct ipu7_insys_resp *ipu7_fw_isys_get_resp(struct ipu7_isys *isys) +{ + return (struct ipu7_insys_resp *) + ipu7_syscom_get_token(isys->adev->syscom, + IPU_INSYS_OUTPUT_MSG_QUEUE); +} + +void ipu7_fw_isys_put_resp(struct ipu7_isys *isys) +{ + ipu7_syscom_put_token(isys->adev->syscom, IPU_INSYS_OUTPUT_MSG_QUEUE); +} + +void ipu7_fw_isys_dump_stream_cfg(struct device *dev, + struct ipu7_insys_stream_cfg *cfg) +{ + unsigned int i; + + dev_dbg(dev, "---------------------------\n"); + dev_dbg(dev, "IPU_FW_ISYS_STREAM_CFG_DATA\n"); + + dev_dbg(dev, ".port id %d\n", cfg->port_id); + dev_dbg(dev, ".vc %d\n", cfg->vc); + dev_dbg(dev, ".nof_input_pins = %d\n", cfg->nof_input_pins); + dev_dbg(dev, ".nof_output_pins = %d\n", cfg->nof_output_pins); + dev_dbg(dev, ".stream_msg_map = 0x%x\n", cfg->stream_msg_map); + + for (i = 0; i < cfg->nof_input_pins; i++) { + dev_dbg(dev, ".input_pin[%d]:\n", i); + dev_dbg(dev, "\t.dt = 0x%0x\n", + cfg->input_pins[i].dt); + dev_dbg(dev, "\t.disable_mipi_unpacking = %d\n", + cfg->input_pins[i].disable_mipi_unpacking); + dev_dbg(dev, "\t.dt_rename_mode = %d\n", + cfg->input_pins[i].dt_rename_mode); + dev_dbg(dev, "\t.mapped_dt = 0x%0x\n", + cfg->input_pins[i].mapped_dt); + dev_dbg(dev, "\t.input_res = %d x %d\n", + cfg->input_pins[i].input_res.width, + cfg->input_pins[i].input_res.height); + dev_dbg(dev, "\t.sync_msg_map = 0x%x\n", + cfg->input_pins[i].sync_msg_map); + } + + for (i = 0; i < cfg->nof_output_pins; i++) { + dev_dbg(dev, ".output_pin[%d]:\n", i); + dev_dbg(dev, "\t.input_pin_id = %d\n", + cfg->output_pins[i].input_pin_id); + dev_dbg(dev, "\t.stride = %d\n", cfg->output_pins[i].stride); + dev_dbg(dev, "\t.send_irq = %d\n", + cfg->output_pins[i].send_irq); + dev_dbg(dev, "\t.ft = %d\n", cfg->output_pins[i].ft); + + dev_dbg(dev, "\t.link.buffer_lines = %d\n", + cfg->output_pins[i].link.buffer_lines); + dev_dbg(dev, "\t.link.foreign_key = %d\n", + cfg->output_pins[i].link.foreign_key); + dev_dbg(dev, "\t.link.granularity_pointer_update = %d\n", + cfg->output_pins[i].link.granularity_pointer_update); + dev_dbg(dev, "\t.link.msg_link_streaming_mode = %d\n", + cfg->output_pins[i].link.msg_link_streaming_mode); + dev_dbg(dev, "\t.link.pbk_id = %d\n", + cfg->output_pins[i].link.pbk_id); + dev_dbg(dev, "\t.link.pbk_slot_id = %d\n", + cfg->output_pins[i].link.pbk_slot_id); + dev_dbg(dev, "\t.link.dest = %d\n", + cfg->output_pins[i].link.dest); + dev_dbg(dev, "\t.link.use_sw_managed = %d\n", + cfg->output_pins[i].link.use_sw_managed); + dev_dbg(dev, "\t.link.is_snoop = %d\n", + cfg->output_pins[i].link.is_snoop); + + dev_dbg(dev, "\t.crop.line_top = %d\n", + cfg->output_pins[i].crop.line_top); + dev_dbg(dev, "\t.crop.line_bottom = %d\n", + cfg->output_pins[i].crop.line_bottom); + + dev_dbg(dev, "\t.dpcm_enable = %d\n", + cfg->output_pins[i].dpcm.enable); + dev_dbg(dev, "\t.dpcm.type = %d\n", + cfg->output_pins[i].dpcm.type); + dev_dbg(dev, "\t.dpcm.predictor = %d\n", + cfg->output_pins[i].dpcm.predictor); + } + dev_dbg(dev, "---------------------------\n"); +} + +void ipu7_fw_isys_dump_frame_buff_set(struct device *dev, + struct ipu7_insys_buffset *buf, + unsigned int outputs) +{ + unsigned int i; + + dev_dbg(dev, "--------------------------\n"); + dev_dbg(dev, "IPU_ISYS_BUFF_SET\n"); + dev_dbg(dev, ".capture_msg_map = %d\n", buf->capture_msg_map); + dev_dbg(dev, ".frame_id = %d\n", buf->frame_id); + dev_dbg(dev, ".skip_frame = %d\n", buf->skip_frame); + + for (i = 0; i < outputs; i++) { + dev_dbg(dev, ".output_pin[%d]:\n", i); + dev_dbg(dev, "\t.user_token = %llx\n", + buf->output_pins[i].user_token); + dev_dbg(dev, "\t.addr = 0x%x\n", buf->output_pins[i].addr); + } + dev_dbg(dev, "---------------------------\n"); +} diff --git a/drivers/staging/media/ipu7/ipu7-fw-isys.h b/drivers/staging/media/ipu7/ipu7-fw-isys.h new file mode 100644 index 0000000000000..b556feda6b08f --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-fw-isys.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#ifndef IPU7_FW_ISYS_H +#define IPU7_FW_ISYS_H + +#include <linux/types.h> + +#include "abi/ipu7_fw_isys_abi.h" + +struct device; +struct ipu7_insys_buffset; +struct ipu7_insys_stream_cfg; +struct ipu7_isys; + +/* From here on type defines not coming from the ISYSAPI interface */ + +int ipu7_fw_isys_init(struct ipu7_isys *isys); +void ipu7_fw_isys_release(struct ipu7_isys *isys); +int ipu7_fw_isys_open(struct ipu7_isys *isys); +int ipu7_fw_isys_close(struct ipu7_isys *isys); + +void ipu7_fw_isys_dump_stream_cfg(struct device *dev, + struct ipu7_insys_stream_cfg *cfg); +void ipu7_fw_isys_dump_frame_buff_set(struct device *dev, + struct ipu7_insys_buffset *buf, + unsigned int outputs); +int ipu7_fw_isys_simple_cmd(struct ipu7_isys *isys, + const unsigned int stream_handle, u16 send_type); +int ipu7_fw_isys_complex_cmd(struct ipu7_isys *isys, + const unsigned int stream_handle, + void *cpu_mapped_buf, + dma_addr_t dma_mapped_buf, + size_t size, u16 send_type); +struct ipu7_insys_resp *ipu7_fw_isys_get_resp(struct ipu7_isys *isys); +void ipu7_fw_isys_put_resp(struct ipu7_isys *isys); +#endif diff --git a/drivers/staging/media/ipu7/ipu7-isys-csi-phy.c b/drivers/staging/media/ipu7/ipu7-isys-csi-phy.c new file mode 100644 index 0000000000000..b8c5db7ae3009 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys-csi-phy.c @@ -0,0 +1,1034 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <linux/bitmap.h> +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/types.h> + +#include <media/mipi-csi2.h> +#include <media/v4l2-device.h> + +#include "ipu7.h" +#include "ipu7-bus.h" +#include "ipu7-buttress.h" +#include "ipu7-isys.h" +#include "ipu7-isys-csi2.h" +#include "ipu7-isys-csi2-regs.h" +#include "ipu7-platform-regs.h" +#include "ipu7-isys-csi-phy.h" + +#define PORT_A 0U +#define PORT_B 1U +#define PORT_C 2U +#define PORT_D 3U + +#define N_DATA_IDS 8U +static DECLARE_BITMAP(data_ids, N_DATA_IDS); + +struct ddlcal_counter_ref_s { + u16 min_mbps; + u16 max_mbps; + + u16 ddlcal_counter_ref; +}; + +struct ddlcal_params { + u16 min_mbps; + u16 max_mbps; + u16 oa_lanex_hsrx_cdphy_sel_fast; + u16 ddlcal_max_phase; + u16 phase_bound; + u16 ddlcal_dll_fbk; + u16 ddlcal_ddl_coarse_bank; + u16 fjump_deskew; + u16 min_eye_opening_deskew; +}; + +struct i_thssettle_params { + u16 min_mbps; + u16 max_mbps; + u16 i_thssettle; +}; + + /* lane2 for 4l3t, lane1 for 2l2t */ +struct oa_lane_clk_div_params { + u16 min_mbps; + u16 max_mbps; + u16 oa_lane_hsrx_hs_clk_div; +}; + +struct cdr_fbk_cap_prog_params { + u16 min_mbps; + u16 max_mbps; + u16 val; +}; + +static const struct ddlcal_counter_ref_s table0[] = { + { 1500, 1999, 118 }, + { 2000, 2499, 157 }, + { 2500, 3499, 196 }, + { 3500, 4499, 274 }, + { 4500, 4500, 352 }, + { } +}; + +static const struct ddlcal_params table1[] = { + { 1500, 1587, 0, 143, 167, 17, 3, 4, 29 }, + { 1588, 1687, 0, 135, 167, 15, 3, 4, 27 }, + { 1688, 1799, 0, 127, 135, 15, 2, 4, 26 }, + { 1800, 1928, 0, 119, 135, 13, 2, 3, 24 }, + { 1929, 2076, 0, 111, 135, 13, 2, 3, 23 }, + { 2077, 2249, 0, 103, 135, 11, 2, 3, 21 }, + { 2250, 2454, 0, 95, 103, 11, 1, 3, 19 }, + { 2455, 2699, 0, 87, 103, 9, 1, 3, 18 }, + { 2700, 2999, 0, 79, 103, 9, 1, 2, 16 }, + { 3000, 3229, 0, 71, 71, 7, 1, 2, 15 }, + { 3230, 3599, 1, 87, 103, 9, 1, 3, 18 }, + { 3600, 3999, 1, 79, 103, 9, 1, 2, 16 }, + { 4000, 4499, 1, 71, 103, 7, 1, 2, 15 }, + { 4500, 4500, 1, 63, 71, 7, 0, 2, 13 }, + { } +}; + +static const struct i_thssettle_params table2[] = { + { 80, 124, 24 }, + { 125, 249, 20 }, + { 250, 499, 16 }, + { 500, 749, 14 }, + { 750, 1499, 13 }, + { 1500, 4500, 12 }, + { } +}; + +static const struct oa_lane_clk_div_params table6[] = { + { 80, 159, 0x1 }, + { 160, 319, 0x2 }, + { 320, 639, 0x3 }, + { 640, 1279, 0x4 }, + { 1280, 2560, 0x5 }, + { 2561, 4500, 0x6 }, + { } +}; + +static const struct cdr_fbk_cap_prog_params table7[] = { + { 80, 919, 0 }, + { 920, 1029, 1 }, + { 1030, 1169, 2 }, + { 1170, 1349, 3 }, + { 1350, 1589, 4 }, + { 1590, 1949, 5 }, + { 1950, 2499, 6 }, + { } +}; + +static void dwc_phy_write(struct ipu7_isys *isys, u32 id, u32 addr, u16 data) +{ + void __iomem *isys_base = isys->pdata->base; + void __iomem *base = isys_base + IS_IO_CDPHY_BASE(id); + + dev_dbg(&isys->adev->auxdev.dev, "phy write: reg 0x%zx = data 0x%04x", + base + addr - isys_base, data); + writew(data, base + addr); +} + +static u16 dwc_phy_read(struct ipu7_isys *isys, u32 id, u32 addr) +{ + void __iomem *isys_base = isys->pdata->base; + void __iomem *base = isys_base + IS_IO_CDPHY_BASE(id); + u16 data; + + data = readw(base + addr); + dev_dbg(&isys->adev->auxdev.dev, "phy read: reg 0x%zx = data 0x%04x", + base + addr - isys_base, data); + + return data; +} + +static void dwc_csi_write(struct ipu7_isys *isys, u32 id, u32 addr, u32 data) +{ + void __iomem *isys_base = isys->pdata->base; + void __iomem *base = isys_base + IS_IO_CSI2_HOST_BASE(id); + struct device *dev = &isys->adev->auxdev.dev; + + dev_dbg(dev, "csi write: reg 0x%zx = data 0x%08x", + base + addr - isys_base, data); + writel(data, base + addr); + dev_dbg(dev, "csi read: reg 0x%zx = data 0x%08x", + base + addr - isys_base, readl(base + addr)); +} + +static void gpreg_write(struct ipu7_isys *isys, u32 id, u32 addr, u32 data) +{ + void __iomem *isys_base = isys->pdata->base; + u32 gpreg = isys->pdata->ipdata->csi2.gpreg; + void __iomem *base = isys_base + gpreg + 0x1000 * id; + struct device *dev = &isys->adev->auxdev.dev; + + dev_dbg(dev, "gpreg write: reg 0x%zx = data 0x%08x", + base + addr - isys_base, data); + writel(data, base + addr); + dev_dbg(dev, "gpreg read: reg 0x%zx = data 0x%08x", + base + addr - isys_base, readl(base + addr)); +} + +static u32 dwc_csi_read(struct ipu7_isys *isys, u32 id, u32 addr) +{ + void __iomem *isys_base = isys->pdata->base; + void __iomem *base = isys_base + IS_IO_CSI2_HOST_BASE(id); + u32 data; + + data = readl(base + addr); + dev_dbg(&isys->adev->auxdev.dev, "csi read: reg 0x%zx = data 0x%x", + base + addr - isys_base, data); + + return data; +} + +static void dwc_phy_write_mask(struct ipu7_isys *isys, u32 id, u32 addr, + u16 val, u8 lo, u8 hi) +{ + u32 temp, mask; + + WARN_ON(lo > hi); + WARN_ON(hi > 15); + + mask = ((~0U - (1U << lo) + 1U)) & (~0U >> (31 - hi)); + temp = dwc_phy_read(isys, id, addr); + temp &= ~mask; + temp |= (val << lo) & mask; + dwc_phy_write(isys, id, addr, temp); +} + +static void dwc_csi_write_mask(struct ipu7_isys *isys, u32 id, u32 addr, + u32 val, u8 hi, u8 lo) +{ + u32 temp, mask; + + WARN_ON(lo > hi); + + mask = ((~0U - (1U << lo) + 1U)) & (~0U >> (31 - hi)); + temp = dwc_csi_read(isys, id, addr); + temp &= ~mask; + temp |= (val << lo) & mask; + dwc_csi_write(isys, id, addr, temp); +} + +static void ipu7_isys_csi_ctrl_cfg(struct ipu7_isys_csi2 *csi2) +{ + struct ipu7_isys *isys = csi2->isys; + struct device *dev = &isys->adev->auxdev.dev; + u32 id, lanes, phy_mode; + u32 val; + + id = csi2->port; + lanes = csi2->nlanes; + phy_mode = csi2->phy_mode; + dev_dbg(dev, "csi-%d controller init with %u lanes, phy mode %u", + id, lanes, phy_mode); + + val = dwc_csi_read(isys, id, VERSION); + dev_dbg(dev, "csi-%d controller version = 0x%x", id, val); + + /* num of active data lanes */ + dwc_csi_write(isys, id, N_LANES, lanes - 1); + dwc_csi_write(isys, id, CDPHY_MODE, phy_mode); + dwc_csi_write(isys, id, VC_EXTENSION, 0); + + /* only mask PHY_FATAL and PKT_FATAL interrupts */ + dwc_csi_write(isys, id, INT_MSK_PHY_FATAL, 0xff); + dwc_csi_write(isys, id, INT_MSK_PKT_FATAL, 0x3); + dwc_csi_write(isys, id, INT_MSK_PHY, 0x0); + dwc_csi_write(isys, id, INT_MSK_LINE, 0x0); + dwc_csi_write(isys, id, INT_MSK_BNDRY_FRAME_FATAL, 0x0); + dwc_csi_write(isys, id, INT_MSK_SEQ_FRAME_FATAL, 0x0); + dwc_csi_write(isys, id, INT_MSK_CRC_FRAME_FATAL, 0x0); + dwc_csi_write(isys, id, INT_MSK_PLD_CRC_FATAL, 0x0); + dwc_csi_write(isys, id, INT_MSK_DATA_ID, 0x0); + dwc_csi_write(isys, id, INT_MSK_ECC_CORRECTED, 0x0); +} + +static void ipu7_isys_csi_phy_reset(struct ipu7_isys *isys, u32 id) +{ + dwc_csi_write(isys, id, PHY_SHUTDOWNZ, 0); + dwc_csi_write(isys, id, DPHY_RSTZ, 0); + dwc_csi_write(isys, id, CSI2_RESETN, 0); + gpreg_write(isys, id, PHY_RESET, 0); + gpreg_write(isys, id, PHY_SHUTDOWN, 0); +} + +/* 8 Data ID monitors, each Data ID is composed by pair of VC and data type */ +static int __dids_config(struct ipu7_isys_csi2 *csi2, u32 id, u8 vc, u8 dt) +{ + struct ipu7_isys *isys = csi2->isys; + u32 reg, n; + u8 lo, hi; + int ret; + + dev_dbg(&isys->adev->auxdev.dev, "config CSI-%u with vc:%u dt:0x%02x\n", + id, vc, dt); + + dwc_csi_write(isys, id, VC_EXTENSION, 0x0); + n = find_first_zero_bit(data_ids, N_DATA_IDS); + if (n == N_DATA_IDS) + return -ENOSPC; + + ret = test_and_set_bit(n, data_ids); + if (ret) + return -EBUSY; + + reg = n < 4 ? DATA_IDS_VC_1 : DATA_IDS_VC_2; + lo = (n % 4) * 8; + hi = lo + 4; + dwc_csi_write_mask(isys, id, reg, vc & GENMASK(4, 0), hi, lo); + + reg = n < 4 ? DATA_IDS_1 : DATA_IDS_2; + lo = (n % 4) * 8; + hi = lo + 5; + dwc_csi_write_mask(isys, id, reg, dt & GENMASK(5, 0), hi, lo); + + return 0; +} + +static int ipu7_isys_csi_ctrl_dids_config(struct ipu7_isys_csi2 *csi2, u32 id) +{ + struct v4l2_mbus_frame_desc_entry *desc_entry = NULL; + struct device *dev = &csi2->isys->adev->auxdev.dev; + struct v4l2_mbus_frame_desc desc; + struct v4l2_subdev *ext_sd; + struct media_pad *pad; + unsigned int i; + int ret; + + pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity); + if (IS_ERR(pad)) { + dev_warn(dev, "can't get remote source pad of %s (%ld)\n", + csi2->asd.sd.name, PTR_ERR(pad)); + return PTR_ERR(pad); + } + + ext_sd = media_entity_to_v4l2_subdev(pad->entity); + if (WARN(!ext_sd, "Failed to get subdev for entity %s\n", + pad->entity->name)) + return -ENODEV; + + ret = v4l2_subdev_call(ext_sd, pad, get_frame_desc, pad->index, &desc); + if (ret) + return ret; + + if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { + dev_warn(dev, "Unsupported frame descriptor type\n"); + return -EINVAL; + } + + for (i = 0; i < desc.num_entries; i++) { + desc_entry = &desc.entry[i]; + if (desc_entry->bus.csi2.vc < IPU7_NR_OF_CSI2_VC) { + ret = __dids_config(csi2, id, desc_entry->bus.csi2.vc, + desc_entry->bus.csi2.dt); + if (ret) + return ret; + } + } + + return 0; +} + +#define CDPHY_TIMEOUT 5000000U +static int ipu7_isys_phy_ready(struct ipu7_isys *isys, u32 id) +{ + void __iomem *isys_base = isys->pdata->base; + u32 gpreg_offset = isys->pdata->ipdata->csi2.gpreg; + void __iomem *gpreg = isys_base + gpreg_offset + 0x1000 * id; + struct device *dev = &isys->adev->auxdev.dev; + unsigned int i; + u32 phy_ready; + u32 reg, rext; + int ret; + + dev_dbg(dev, "waiting phy ready...\n"); + ret = readl_poll_timeout(gpreg + PHY_READY, phy_ready, + phy_ready & BIT(0) && phy_ready != ~0U, + 100, CDPHY_TIMEOUT); + dev_dbg(dev, "phy %u ready = 0x%08x\n", id, readl(gpreg + PHY_READY)); + dev_dbg(dev, "csi %u PHY_RX = 0x%08x\n", id, + dwc_csi_read(isys, id, PHY_RX)); + dev_dbg(dev, "csi %u PHY_STOPSTATE = 0x%08x\n", id, + dwc_csi_read(isys, id, PHY_STOPSTATE)); + dev_dbg(dev, "csi %u PHY_CAL = 0x%08x\n", id, + dwc_csi_read(isys, id, PHY_CAL)); + for (i = 0; i < 4U; i++) { + reg = CORE_DIG_DLANE_0_R_HS_RX_0 + (i * 0x400U); + dev_dbg(dev, "phy %u DLANE%u skewcal = 0x%04x\n", + id, i, dwc_phy_read(isys, id, reg)); + } + dev_dbg(dev, "phy %u DDLCAL = 0x%04x\n", id, + dwc_phy_read(isys, id, PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_5)); + dev_dbg(dev, "phy %u TERMCAL = 0x%04x\n", id, + dwc_phy_read(isys, id, PPI_R_TERMCAL_DEBUG_0)); + dev_dbg(dev, "phy %u LPDCOCAL = 0x%04x\n", id, + dwc_phy_read(isys, id, PPI_R_LPDCOCAL_DEBUG_RB)); + dev_dbg(dev, "phy %u HSDCOCAL = 0x%04x\n", id, + dwc_phy_read(isys, id, PPI_R_HSDCOCAL_DEBUG_RB)); + dev_dbg(dev, "phy %u LPDCOCAL_VT = 0x%04x\n", id, + dwc_phy_read(isys, id, PPI_R_LPDCOCAL_DEBUG_VT)); + + if (!ret) { + if (id) { + dev_dbg(dev, "ignore phy %u rext\n", id); + return 0; + } + + rext = dwc_phy_read(isys, id, + CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_15) & 0xfU; + dev_dbg(dev, "phy %u rext value = %u\n", id, rext); + isys->phy_rext_cal = (rext ? rext : 5); + + return 0; + } + + dev_err(dev, "wait phy ready timeout!\n"); + + return ret; +} + +static int lookup_table1(u64 mbps) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(table1); i++) { + if (mbps >= table1[i].min_mbps && mbps <= table1[i].max_mbps) + return i; + } + + return -ENXIO; +} + +static const u16 deskew_fine_mem[] = { + 0x0404, 0x040c, 0x0414, 0x041c, + 0x0423, 0x0429, 0x0430, 0x043a, + 0x0445, 0x044a, 0x0450, 0x045a, + 0x0465, 0x0469, 0x0472, 0x047a, + 0x0485, 0x0489, 0x0490, 0x049a, + 0x04a4, 0x04ac, 0x04b4, 0x04bc, + 0x04c4, 0x04cc, 0x04d4, 0x04dc, + 0x04e4, 0x04ec, 0x04f4, 0x04fc, + 0x0504, 0x050c, 0x0514, 0x051c, + 0x0523, 0x0529, 0x0530, 0x053a, + 0x0545, 0x054a, 0x0550, 0x055a, + 0x0565, 0x0569, 0x0572, 0x057a, + 0x0585, 0x0589, 0x0590, 0x059a, + 0x05a4, 0x05ac, 0x05b4, 0x05bc, + 0x05c4, 0x05cc, 0x05d4, 0x05dc, + 0x05e4, 0x05ec, 0x05f4, 0x05fc, + 0x0604, 0x060c, 0x0614, 0x061c, + 0x0623, 0x0629, 0x0632, 0x063a, + 0x0645, 0x064a, 0x0650, 0x065a, + 0x0665, 0x0669, 0x0672, 0x067a, + 0x0685, 0x0689, 0x0690, 0x069a, + 0x06a4, 0x06ac, 0x06b4, 0x06bc, + 0x06c4, 0x06cc, 0x06d4, 0x06dc, + 0x06e4, 0x06ec, 0x06f4, 0x06fc, + 0x0704, 0x070c, 0x0714, 0x071c, + 0x0723, 0x072a, 0x0730, 0x073a, + 0x0745, 0x074a, 0x0750, 0x075a, + 0x0765, 0x0769, 0x0772, 0x077a, + 0x0785, 0x0789, 0x0790, 0x079a, + 0x07a4, 0x07ac, 0x07b4, 0x07bc, + 0x07c4, 0x07cc, 0x07d4, 0x07dc, + 0x07e4, 0x07ec, 0x07f4, 0x07fc, +}; + +static void ipu7_isys_dphy_config(struct ipu7_isys *isys, u8 id, u8 lanes, + bool aggregation, u64 mbps) +{ + u16 hsrxval0 = 0; + u16 hsrxval1 = 0; + u16 hsrxval2 = 0; + int index; + u16 reg; + u16 val; + u32 i; + + dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_7, 0, 0, 9); + if (mbps > 1500) + dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7, + 40, 0, 7); + else + dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7, + 104, 0, 7); + + dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_8, 80, 0, 7); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_0, 191, 0, 9); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_7, 34, 7, 12); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_1, 38, 8, 15); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 4, 12, 15); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 2, 10, 11); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 1, 8, 8); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 38, 0, 7); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 1, 9, 9); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_4, 10, 0, 9); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_6, 20, 0, 9); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_7, 19, 0, 6); + + for (i = 0; i < ARRAY_SIZE(table0); i++) { + if (mbps >= table0[i].min_mbps && mbps <= table0[i].max_mbps) { + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_3, + table0[i].ddlcal_counter_ref, + 0, 9); + break; + } + } + + index = lookup_table1(mbps); + if (index >= 0) { + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_1, + table1[index].phase_bound, 0, 7); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_5, + table1[index].ddlcal_dll_fbk, 4, 9); + dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_5, + table1[index].ddlcal_ddl_coarse_bank, 0, 3); + + reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_8; + val = table1[index].oa_lanex_hsrx_cdphy_sel_fast; + for (i = 0; i < lanes + 1; i++) + dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, + 12, 12); + } + + reg = CORE_DIG_DLANE_0_RW_LP_0; + for (i = 0; i < lanes; i++) + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 6, 8, 11); + + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2, + 0, 0, 0); + if (!is_ipu7(isys->adev->isp->hw_ver) || + id == PORT_B || id == PORT_C) { + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2, + 1, 0, 0); + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2, + 0, 0, 0); + } else { + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2, + 0, 0, 0); + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2, + 1, 0, 0); + } + + if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) { + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2, + 0, 0, 0); + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2, + 0, 0, 0); + } + + dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_6, 1, 0, 2); + dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_6, 1, 3, 5); + + reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_12; + val = (mbps > 1500) ? 0 : 1; + for (i = 0; i < lanes + 1; i++) { + dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1); + dwc_phy_write_mask(isys, id, reg + (i * 0x400), !val, 3, 3); + } + + reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_13; + val = (mbps > 1500) ? 0 : 1; + for (i = 0; i < lanes + 1; i++) { + dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1); + dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 3, 3); + } + + if (!is_ipu7(isys->adev->isp->hw_ver) || id == PORT_B || id == PORT_C) + reg = CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9; + else + reg = CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9; + + for (i = 0; i < ARRAY_SIZE(table6); i++) { + if (mbps >= table6[i].min_mbps && mbps <= table6[i].max_mbps) { + dwc_phy_write_mask(isys, id, reg, + table6[i].oa_lane_hsrx_hs_clk_div, + 5, 7); + break; + } + } + + if (aggregation) { + dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_0, 1, + 1, 1); + + reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15; + dwc_phy_write_mask(isys, id, reg, 3, 3, 4); + + val = (id == PORT_A) ? 3 : 0; + reg = CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15; + dwc_phy_write_mask(isys, id, reg, val, 3, 4); + + reg = CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15; + dwc_phy_write_mask(isys, id, reg, 3, 3, 4); + } + + dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_HS_RX_0, 28, 0, 7); + dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_HS_RX_7, 6, 0, 7); + + reg = CORE_DIG_DLANE_0_RW_HS_RX_0; + for (i = 0; i < ARRAY_SIZE(table2); i++) { + if (mbps >= table2[i].min_mbps && mbps <= table2[i].max_mbps) { + u8 j; + + for (j = 0; j < lanes; j++) + dwc_phy_write_mask(isys, id, reg + (j * 0x400), + table2[i].i_thssettle, + 8, 15); + break; + } + } + + /* deskew */ + for (i = 0; i < lanes; i++) { + reg = CORE_DIG_DLANE_0_RW_CFG_1; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), + ((mbps > 1500) ? 0x1 : 0x2), 2, 3); + + reg = CORE_DIG_DLANE_0_RW_HS_RX_2; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), + ((mbps > 2500) ? 0 : 1), 15, 15); + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 13, 13); + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 7, 9, 12); + + reg = CORE_DIG_DLANE_0_RW_LP_0; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 12, 15); + + reg = CORE_DIG_DLANE_0_RW_LP_2; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 0, 0); + + reg = CORE_DIG_DLANE_0_RW_HS_RX_1; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 16, 0, 7); + + reg = CORE_DIG_DLANE_0_RW_HS_RX_3; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 2, 0, 2); + index = lookup_table1(mbps); + if (index >= 0) { + val = table1[index].fjump_deskew; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, + 3, 8); + } + + reg = CORE_DIG_DLANE_0_RW_HS_RX_4; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 150, 0, 15); + + reg = CORE_DIG_DLANE_0_RW_HS_RX_5; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 0, 7); + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 8, 15); + + reg = CORE_DIG_DLANE_0_RW_HS_RX_6; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 2, 0, 7); + index = lookup_table1(mbps); + if (index >= 0) { + val = table1[index].min_eye_opening_deskew; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, + 8, 15); + } + reg = CORE_DIG_DLANE_0_RW_HS_RX_7; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 13, 13); + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 15, 15); + + reg = CORE_DIG_DLANE_0_RW_HS_RX_9; + index = lookup_table1(mbps); + if (index >= 0) { + val = table1[index].ddlcal_max_phase; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), + val, 0, 7); + } + } + + dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_LP_0, 1, 12, 15); + dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_LP_2, 0, 0, 0); + + for (i = 0; i < ARRAY_SIZE(deskew_fine_mem); i++) + dwc_phy_write_mask(isys, id, CORE_DIG_COMMON_RW_DESKEW_FINE_MEM, + deskew_fine_mem[i], 0, 15); + + if (mbps > 1500) { + hsrxval0 = 4; + hsrxval2 = 3; + } + + if (mbps > 2500) + hsrxval1 = 2; + + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9, + hsrxval0, 0, 2); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9, + hsrxval0, 0, 2); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9, + hsrxval0, 0, 2); + if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) { + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9, + hsrxval0, 0, 2); + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9, + hsrxval0, 0, 2); + } + + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9, + hsrxval1, 3, 4); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9, + hsrxval1, 3, 4); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9, + hsrxval1, 3, 4); + if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) { + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9, + hsrxval1, 3, 4); + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9, + hsrxval1, 3, 4); + } + + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15, + hsrxval2, 0, 2); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15, + hsrxval2, 0, 2); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15, + hsrxval2, 0, 2); + if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) { + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_15, + hsrxval2, 0, 2); + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_15, + hsrxval2, 0, 2); + } + + /* force and override rext */ + if (isys->phy_rext_cal && id) { + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_8, + isys->phy_rext_cal, 0, 3); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7, + 1, 11, 11); + } +} + +static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes, + bool aggregation, u64 mbps) +{ + u8 trios = 2; + u16 coarse_target; + u16 deass_thresh; + u16 delay_thresh; + u16 reset_thresh; + u16 cap_prog = 6U; + u16 reg; + u16 val; + u32 i; + u64 r64; + u32 r; + + if (is_ipu7p5(isys->adev->isp->hw_ver)) + val = 0x15; + else + val = 0x155; + + if (is_ipu7(isys->adev->isp->hw_ver)) + trios = 3; + + dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_7, val, 0, 9); + dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7, 104, 0, 7); + dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_8, 16, 0, 7); + + reg = CORE_DIG_CLANE_0_RW_LP_0; + for (i = 0; i < trios; i++) + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 6, 8, 11); + + val = (mbps > 900U) ? 1U : 0U; + for (i = 0; i < trios; i++) { + reg = CORE_DIG_CLANE_0_RW_HS_RX_0; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 0, 0); + dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1); + + reg = CORE_DIG_CLANE_0_RW_HS_RX_1; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 38, 0, 15); + + reg = CORE_DIG_CLANE_0_RW_HS_RX_5; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 38, 0, 15); + + reg = CORE_DIG_CLANE_0_RW_HS_RX_6; + dwc_phy_write_mask(isys, id, reg + (i * 0x400), 10, 0, 15); + } + + /* + * Below 900Msps, always use the same value. + * The formula is suitable for data rate 80-3500Msps. + * Timebase (us) = 1, DIV = 32, TDDL (UI) = 0.5 + */ + if (mbps >= 80U) + coarse_target = DIV_ROUND_UP_ULL(mbps, 16) - 1; + else + coarse_target = 56; + + for (i = 0; i < trios; i++) { + reg = CORE_DIG_CLANE_0_RW_HS_RX_2 + i * 0x400; + dwc_phy_write_mask(isys, id, reg, coarse_target, 0, 15); + } + + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2, 1, 0, 0); + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2, 0, 0, 0); + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2, 1, 0, 0); + + if (!is_ipu7p5(isys->adev->isp->hw_ver) && lanes == 4) { + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2, + 1, 0, 0); + dwc_phy_write_mask(isys, id, + CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2, + 0, 0, 0); + } + + for (i = 0; i < trios; i++) { + reg = CORE_DIG_RW_TRIO0_0 + i * 0x400; + dwc_phy_write_mask(isys, id, reg, 1, 6, 8); + dwc_phy_write_mask(isys, id, reg, 1, 3, 5); + dwc_phy_write_mask(isys, id, reg, 2, 0, 2); + } + + deass_thresh = (u16)div64_u64_rem(7 * 1000 * 6, mbps * 5U, &r64) + 1; + if (r64 != 0) + deass_thresh++; + + reg = CORE_DIG_RW_TRIO0_2; + for (i = 0; i < trios; i++) + dwc_phy_write_mask(isys, id, reg + 0x400 * i, + deass_thresh, 0, 7); + + delay_thresh = div64_u64((224U - (9U * 7U)) * 1000U, 5U * mbps) - 7u; + + if (delay_thresh < 1) + delay_thresh = 1; + + reg = CORE_DIG_RW_TRIO0_1; + for (i = 0; i < trios; i++) + dwc_phy_write_mask(isys, id, reg + 0x400 * i, + delay_thresh, 0, 15); + + reset_thresh = (u16)div_u64_rem(2U * 5U * mbps, 7U * 1000U, &r); + if (!r) + reset_thresh--; + + if (reset_thresh < 1) + reset_thresh = 1; + + reg = CORE_DIG_RW_TRIO0_0; + for (i = 0; i < trios; i++) + dwc_phy_write_mask(isys, id, reg + 0x400 * i, + reset_thresh, 9, 11); + + reg = CORE_DIG_CLANE_0_RW_LP_0; + for (i = 0; i < trios; i++) + dwc_phy_write_mask(isys, id, reg + 0x400 * i, 1, 12, 15); + + reg = CORE_DIG_CLANE_0_RW_LP_2; + for (i = 0; i < trios; i++) + dwc_phy_write_mask(isys, id, reg + 0x400 * i, 0, 0, 0); + + reg = CORE_DIG_CLANE_0_RW_HS_RX_0; + for (i = 0; i < trios; i++) + dwc_phy_write_mask(isys, id, reg + 0x400 * i, 12, 2, 6); + + for (i = 0; i < ARRAY_SIZE(table7); i++) { + if (mbps >= table7[i].min_mbps && mbps <= table7[i].max_mbps) { + cap_prog = table7[i].val; + break; + } + } + + for (i = 0; i < (lanes + 1); i++) { + reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9 + 0x400 * i; + dwc_phy_write_mask(isys, id, reg, 4U, 0, 2); + dwc_phy_write_mask(isys, id, reg, 0U, 3, 4); + + reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_7 + 0x400 * i; + dwc_phy_write_mask(isys, id, reg, cap_prog, 10, 12); + } +} + +static int ipu7_isys_phy_config(struct ipu7_isys *isys, u8 id, u8 lanes, + bool aggregation) +{ + struct device *dev = &isys->adev->auxdev.dev; + u32 phy_mode; + s64 link_freq; + u64 mbps; + + if (aggregation) + link_freq = ipu7_isys_csi2_get_link_freq(&isys->csi2[0]); + else + link_freq = ipu7_isys_csi2_get_link_freq(&isys->csi2[id]); + + if (link_freq < 0) { + dev_err(dev, "get link freq failed (%lld)\n", link_freq); + return link_freq; + } + + mbps = div_u64(link_freq, 500000); + dev_dbg(dev, "config phy %u with lanes %u aggregation %d mbps %lld\n", + id, lanes, aggregation, mbps); + + dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_10, 48, 0, 7); + dwc_phy_write_mask(isys, id, CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2, + 1, 12, 13); + dwc_phy_write_mask(isys, id, CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0, + 63, 2, 7); + dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_STARTUP_1_1, + 563, 0, 11); + dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_2, 5, 0, 7); + /* bypass the RCAL state (bit6) */ + if (aggregation && id != PORT_A) + dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_2, 0x45, + 0, 7); + + dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_6, 39, 0, 7); + dwc_phy_write_mask(isys, id, PPI_CALIBCTRL_RW_COMMON_BG_0, 500, 0, 8); + dwc_phy_write_mask(isys, id, PPI_RW_TERMCAL_CFG_0, 38, 0, 6); + dwc_phy_write_mask(isys, id, PPI_RW_OFFSETCAL_CFG_0, 7, 0, 4); + dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_TIMEBASE, 153, 0, 9); + dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_NREF, 800, 0, 10); + dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_NREF_RANGE, 27, 0, 4); + dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_TWAIT_CONFIG, 47, 0, 8); + dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_TWAIT_CONFIG, 127, 9, 15); + dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_VT_CONFIG, 47, 7, 15); + dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_VT_CONFIG, 27, 2, 6); + dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_VT_CONFIG, 3, 0, 1); + dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_COARSE_CFG, 1, 0, 1); + dwc_phy_write_mask(isys, id, PPI_RW_COMMON_CFG, 3, 0, 1); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0, + 0, 10, 10); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1, + 1, 10, 10); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1, + 0, 15, 15); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_3, + 3, 8, 9); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0, + 0, 15, 15); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_6, + 7, 12, 14); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7, + 0, 8, 10); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_5, + 0, 8, 8); + + if (aggregation) + phy_mode = isys->csi2[0].phy_mode; + else + phy_mode = isys->csi2[id].phy_mode; + + if (phy_mode == PHY_MODE_DPHY) { + ipu7_isys_dphy_config(isys, id, lanes, aggregation, mbps); + } else if (phy_mode == PHY_MODE_CPHY) { + ipu7_isys_cphy_config(isys, id, lanes, aggregation, mbps); + } else { + dev_err(dev, "unsupported phy mode %d!\n", + isys->csi2[id].phy_mode); + } + + return 0; +} + +int ipu7_isys_csi_phy_powerup(struct ipu7_isys_csi2 *csi2) +{ + struct ipu7_isys *isys = csi2->isys; + u32 lanes = csi2->nlanes; + bool aggregation = false; + u32 id = csi2->port; + int ret; + + /* lanes remapping for aggregation (port AB) mode */ + if (!is_ipu7(isys->adev->isp->hw_ver) && lanes > 2 && id == PORT_A) { + aggregation = true; + lanes = 2; + } + + ipu7_isys_csi_phy_reset(isys, id); + gpreg_write(isys, id, PHY_CLK_LANE_CONTROL, 0x1); + gpreg_write(isys, id, PHY_CLK_LANE_FORCE_CONTROL, 0x2); + gpreg_write(isys, id, PHY_LANE_CONTROL_EN, (1U << lanes) - 1U); + gpreg_write(isys, id, PHY_LANE_FORCE_CONTROL, 0xf); + gpreg_write(isys, id, PHY_MODE, csi2->phy_mode); + + /* config PORT_B if aggregation mode */ + if (aggregation) { + ipu7_isys_csi_phy_reset(isys, PORT_B); + gpreg_write(isys, PORT_B, PHY_CLK_LANE_CONTROL, 0x0); + gpreg_write(isys, PORT_B, PHY_LANE_CONTROL_EN, 0x3); + gpreg_write(isys, PORT_B, PHY_CLK_LANE_FORCE_CONTROL, 0x2); + gpreg_write(isys, PORT_B, PHY_LANE_FORCE_CONTROL, 0xf); + gpreg_write(isys, PORT_B, PHY_MODE, csi2->phy_mode); + } + + ipu7_isys_csi_ctrl_cfg(csi2); + ipu7_isys_csi_ctrl_dids_config(csi2, id); + + ret = ipu7_isys_phy_config(isys, id, lanes, aggregation); + if (ret < 0) + return ret; + + gpreg_write(isys, id, PHY_RESET, 1); + gpreg_write(isys, id, PHY_SHUTDOWN, 1); + dwc_csi_write(isys, id, DPHY_RSTZ, 1); + dwc_csi_write(isys, id, PHY_SHUTDOWNZ, 1); + dwc_csi_write(isys, id, CSI2_RESETN, 1); + + ret = ipu7_isys_phy_ready(isys, id); + if (ret < 0) + return ret; + + gpreg_write(isys, id, PHY_LANE_FORCE_CONTROL, 0); + gpreg_write(isys, id, PHY_CLK_LANE_FORCE_CONTROL, 0); + + /* config PORT_B if aggregation mode */ + if (aggregation) { + ret = ipu7_isys_phy_config(isys, PORT_B, 2, aggregation); + if (ret < 0) + return ret; + + gpreg_write(isys, PORT_B, PHY_RESET, 1); + gpreg_write(isys, PORT_B, PHY_SHUTDOWN, 1); + dwc_csi_write(isys, PORT_B, DPHY_RSTZ, 1); + dwc_csi_write(isys, PORT_B, PHY_SHUTDOWNZ, 1); + dwc_csi_write(isys, PORT_B, CSI2_RESETN, 1); + ret = ipu7_isys_phy_ready(isys, PORT_B); + if (ret < 0) + return ret; + + gpreg_write(isys, PORT_B, PHY_LANE_FORCE_CONTROL, 0); + gpreg_write(isys, PORT_B, PHY_CLK_LANE_FORCE_CONTROL, 0); + } + + return 0; +} + +void ipu7_isys_csi_phy_powerdown(struct ipu7_isys_csi2 *csi2) +{ + struct ipu7_isys *isys = csi2->isys; + + ipu7_isys_csi_phy_reset(isys, csi2->port); + if (!is_ipu7(isys->adev->isp->hw_ver) && + csi2->nlanes > 2U && csi2->port == PORT_A) + ipu7_isys_csi_phy_reset(isys, PORT_B); +} diff --git a/drivers/staging/media/ipu7/ipu7-isys-csi-phy.h b/drivers/staging/media/ipu7/ipu7-isys-csi-phy.h new file mode 100644 index 0000000000000..dfdcb61540c4d --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys-csi-phy.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#ifndef IPU7_ISYS_CSI_PHY_H +#define IPU7_ISYS_CSI_PHY_H + +struct ipu7_isys; + +#define PHY_MODE_DPHY 0U +#define PHY_MODE_CPHY 1U + +int ipu7_isys_csi_phy_powerup(struct ipu7_isys_csi2 *csi2); +void ipu7_isys_csi_phy_powerdown(struct ipu7_isys_csi2 *csi2); +#endif diff --git a/drivers/staging/media/ipu7/ipu7-isys-csi2-regs.h b/drivers/staging/media/ipu7/ipu7-isys-csi2-regs.h new file mode 100644 index 0000000000000..aad52c44a0056 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys-csi2-regs.h @@ -0,0 +1,1197 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 - 2025 Intel Corporation + */ + +#ifndef IPU7_ISYS_CSI2_REG_H +#define IPU7_ISYS_CSI2_REG_H + +/* IS main regs base */ +#define IS_MAIN_BASE 0x240000 +#define IS_MAIN_S2B_BASE (IS_MAIN_BASE + 0x22000) +#define IS_MAIN_B2O_BASE (IS_MAIN_BASE + 0x26000) +#define IS_MAIN_ISD_M0_BASE (IS_MAIN_BASE + 0x2b000) +#define IS_MAIN_ISD_M1_BASE (IS_MAIN_BASE + 0x2b100) +#define IS_MAIN_ISD_INT_BASE (IS_MAIN_BASE + 0x2b200) +#define IS_MAIN_GDA_BASE (IS_MAIN_BASE + 0x32000) +#define IS_MAIN_GPREGS_MAIN_BASE (IS_MAIN_BASE + 0x32500) +#define IS_MAIN_IRQ_CTRL_BASE (IS_MAIN_BASE + 0x32700) +#define IS_MAIN_PWM_CTRL_BASE (IS_MAIN_BASE + 0x32b00) + +#define S2B_IRQ_COMMON_0_CTL_STATUS (IS_MAIN_S2B_BASE + 0x1c) +#define S2B_IRQ_COMMON_0_CTL_CLEAR (IS_MAIN_S2B_BASE + 0x20) +#define S2B_IRQ_COMMON_0_CTL_ENABLE (IS_MAIN_S2B_BASE + 0x24) +#define S2B_IID_IRQ_CTL_STATUS(iid) (IS_MAIN_S2B_BASE + 0x94 + \ + 0x100 * (iid)) + +#define B2O_IRQ_COMMON_0_CTL_STATUS (IS_MAIN_B2O_BASE + 0x30) +#define B2O_IRQ_COMMON_0_CTL_CLEAR (IS_MAIN_B2O_BASE + 0x34) +#define B2O_IRQ_COMMON_0_CTL_ENABLE (IS_MAIN_B2O_BASE + 0x38) +#define B2O_IID_IRQ_CTL_STATUS(oid) (IS_MAIN_B2O_BASE + 0x3dc + \ + 0x200 * (oid)) + +#define ISD_M0_IRQ_CTL_STATUS (IS_MAIN_ISD_M0_BASE + 0x1c) +#define ISD_M0_IRQ_CTL_CLEAR (IS_MAIN_ISD_M0_BASE + 0x20) +#define ISD_M0_IRQ_CTL_ENABLE (IS_MAIN_ISD_M0_BASE + 0x24) + +#define ISD_M1_IRQ_CTL_STATUS (IS_MAIN_ISD_M1_BASE + 0x1c) +#define ISD_M1_IRQ_CTL_CLEAR (IS_MAIN_ISD_M1_BASE + 0x20) +#define ISD_M1_IRQ_CTL_ENABLE (IS_MAIN_ISD_M1_BASE + 0x24) + +#define ISD_INT_IRQ_CTL_STATUS (IS_MAIN_ISD_INT_BASE + 0x1c) +#define ISD_INT_IRQ_CTL_CLEAR (IS_MAIN_ISD_INT_BASE + 0x20) +#define ISD_INT_IRQ_CTL_ENABLE (IS_MAIN_ISD_INT_BASE + 0x24) + +#define GDA_IRQ_CTL_STATUS (IS_MAIN_GDA_BASE + 0x1c) +#define GDA_IRQ_CTL_CLEAR (IS_MAIN_GDA_BASE + 0x20) +#define GDA_IRQ_CTL_ENABLE (IS_MAIN_GDA_BASE + 0x24) + +#define IS_MAIN_IRQ_CTL_EDGE IS_MAIN_IRQ_CTRL_BASE +#define IS_MAIN_IRQ_CTL_MASK (IS_MAIN_IRQ_CTRL_BASE + 0x4) +#define IS_MAIN_IRQ_CTL_STATUS (IS_MAIN_IRQ_CTRL_BASE + 0x8) +#define IS_MAIN_IRQ_CTL_CLEAR (IS_MAIN_IRQ_CTRL_BASE + 0xc) +#define IS_MAIN_IRQ_CTL_ENABLE (IS_MAIN_IRQ_CTRL_BASE + 0x10) +#define IS_MAIN_IRQ_CTL_LEVEL_NOT_PULSE (IS_MAIN_IRQ_CTRL_BASE + 0x14) + +/* IS IO regs base */ +#define IS_PHY_NUM 4U +#define IS_IO_BASE 0x280000 + +/* dwc csi cdphy registers */ +#define IS_IO_CDPHY_BASE(i) (IS_IO_BASE + 0x10000 * (i)) +#define PPI_STARTUP_RW_COMMON_DPHY_0 0x1800 +#define PPI_STARTUP_RW_COMMON_DPHY_1 0x1802 +#define PPI_STARTUP_RW_COMMON_DPHY_2 0x1804 +#define PPI_STARTUP_RW_COMMON_DPHY_3 0x1806 +#define PPI_STARTUP_RW_COMMON_DPHY_4 0x1808 +#define PPI_STARTUP_RW_COMMON_DPHY_5 0x180a +#define PPI_STARTUP_RW_COMMON_DPHY_6 0x180c +#define PPI_STARTUP_RW_COMMON_DPHY_7 0x180e +#define PPI_STARTUP_RW_COMMON_DPHY_8 0x1810 +#define PPI_STARTUP_RW_COMMON_DPHY_9 0x1812 +#define PPI_STARTUP_RW_COMMON_DPHY_A 0x1814 +#define PPI_STARTUP_RW_COMMON_DPHY_10 0x1820 +#define PPI_STARTUP_RW_COMMON_STARTUP_1_1 0x1822 +#define PPI_STARTUP_RW_COMMON_STARTUP_1_2 0x1824 +#define PPI_CALIBCTRL_RW_COMMON_CALIBCTRL_2_0 0x1840 +#define PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_1 0x1842 +#define PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_2 0x1844 +#define PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_3 0x1846 +#define PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_4 0x1848 +#define PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_5 0x184a +#define PPI_CALIBCTRL_RW_COMMON_BG_0 0x184c +#define PPI_CALIBCTRL_RW_COMMON_CALIBCTRL_2_7 0x184e +#define PPI_CALIBCTRL_RW_ADC_CFG_0 0x1850 +#define PPI_CALIBCTRL_RW_ADC_CFG_1 0x1852 +#define PPI_CALIBCTRL_R_ADC_DEBUG 0x1854 +#define PPI_RW_LPDCOCAL_TOP_OVERRIDE 0x1c00 +#define PPI_RW_LPDCOCAL_TIMEBASE 0x1c02 +#define PPI_RW_LPDCOCAL_NREF 0x1c04 +#define PPI_RW_LPDCOCAL_NREF_RANGE 0x1c06 +#define PPI_RW_LPDCOCAL_NREF_TRIGGER_MAN 0x1c08 +#define PPI_RW_LPDCOCAL_TWAIT_CONFIG 0x1c0a +#define PPI_RW_LPDCOCAL_VT_CONFIG 0x1c0c +#define PPI_R_LPDCOCAL_DEBUG_RB 0x1c0e +#define PPI_RW_LPDCOCAL_COARSE_CFG 0x1c10 +#define PPI_R_LPDCOCAL_DEBUG_COARSE_RB 0x1c12 +#define PPI_R_LPDCOCAL_DEBUG_COARSE_MEAS_0_RB 0x1c14 +#define PPI_R_LPDCOCAL_DEBUG_COARSE_MEAS_1_RB 0x1c16 +#define PPI_R_LPDCOCAL_DEBUG_COARSE_FWORD_RB 0x1c18 +#define PPI_R_LPDCOCAL_DEBUG_MEASURE_CURR_ERROR 0x1c1a +#define PPI_R_LPDCOCAL_DEBUG_MEASURE_LAST_ERROR 0x1c1c +#define PPI_R_LPDCOCAL_DEBUG_VT 0x1c1e +#define PPI_RW_LB_TIMEBASE_CONFIG 0x1c20 +#define PPI_RW_LB_STARTCMU_CONFIG 0x1c22 +#define PPI_R_LBPULSE_COUNTER_RB 0x1c24 +#define PPI_R_LB_START_CMU_RB 0x1c26 +#define PPI_RW_LB_DPHY_BURST_START 0x1c28 +#define PPI_RW_LB_CPHY_BURST_START 0x1c2a +#define PPI_RW_DDLCAL_CFG_0 0x1c40 +#define PPI_RW_DDLCAL_CFG_1 0x1c42 +#define PPI_RW_DDLCAL_CFG_2 0x1c44 +#define PPI_RW_DDLCAL_CFG_3 0x1c46 +#define PPI_RW_DDLCAL_CFG_4 0x1c48 +#define PPI_RW_DDLCAL_CFG_5 0x1c4a +#define PPI_RW_DDLCAL_CFG_6 0x1c4c +#define PPI_RW_DDLCAL_CFG_7 0x1c4e +#define PPI_R_DDLCAL_DEBUG_0 0x1c50 +#define PPI_R_DDLCAL_DEBUG_1 0x1c52 +#define PPI_RW_PARITY_TEST 0x1c60 +#define PPI_RW_STARTUP_OVR_0 0x1c62 +#define PPI_RW_STARTUP_STATE_OVR_1 0x1c64 +#define PPI_RW_DTB_SELECTOR 0x1c66 +#define PPI_RW_DPHY_CLK_SPARE 0x1c6a +#define PPI_RW_COMMON_CFG 0x1c6c +#define PPI_RW_TERMCAL_CFG_0 0x1c80 +#define PPI_R_TERMCAL_DEBUG_0 0x1c82 +#define PPI_RW_TERMCAL_CTRL_0 0x1c84 +#define PPI_RW_OFFSETCAL_CFG_0 0x1ca0 +#define PPI_R_OFFSETCAL_DEBUG_LANE0 0x1ca2 +#define PPI_R_OFFSETCAL_DEBUG_LANE1 0x1ca4 +#define PPI_R_OFFSETCAL_DEBUG_LANE2 0x1ca6 +#define PPI_R_OFFSETCAL_DEBUG_LANE3 0x1ca8 +#define PPI_R_OFFSETCAL_DEBUG_LANE4 0x1caa +#define PPI_RW_HSDCOCAL_CFG_O 0x1d00 +#define PPI_RW_HSDCOCAL_CFG_1 0x1d02 +#define PPI_RW_HSDCOCAL_CFG_2 0x1d04 +#define PPI_RW_HSDCOCAL_CFG_3 0x1d06 +#define PPI_RW_HSDCOCAL_CFG_4 0x1d08 +#define PPI_RW_HSDCOCAL_CFG_5 0x1d0a +#define PPI_RW_HSDCOCAL_CFG_6 0x1d0c +#define PPI_RW_HSDCOCAL_CFG_7 0x1d0e +#define PPI_RW_HSDCOCAL_CFG_8 0x1d10 +#define PPI_R_HSDCOCAL_DEBUG_RB 0x1d12 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_0 0x2000 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_1 0x2002 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_2 0x2004 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_3 0x2006 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_4 0x2008 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_5 0x200a +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_6 0x200c +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_7 0x200e +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_8 0x2010 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_9 0x2012 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_10 0x2014 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_11 0x2016 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_12 0x2018 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_13 0x201a +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_14 0x201c +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_15 0x201e +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_0 0x2020 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_1 0x2022 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_2 0x2024 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_3 0x2026 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_4 0x2028 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_5 0x202a +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_6 0x202c +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_7 0x202e +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_8 0x2030 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_9 0x2032 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_10 0x2034 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_11 0x2036 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_12 0x2038 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_13 0x203a +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_14 0x203c +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_15 0x203e +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_0 0x2040 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_1 0x2042 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2 0x2044 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_3 0x2046 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_4 0x2048 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_5 0x204a +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_6 0x204c +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_7 0x204e +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_8 0x2050 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9 0x2052 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_10 0x2054 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_11 0x2056 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_12 0x2058 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_13 0x205a +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_14 0x205c +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15 0x205e +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_0 0x2060 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_1 0x2062 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_2 0x2064 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_3 0x2066 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_4 0x2068 +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_5 0x206a +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_6 0x206c +#define CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_7 0x206e +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_8 0x2070 +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_9 0x2072 +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_10 0x2074 +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_11 0x2076 +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_12 0x2078 +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_13 0x207a +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_14 0x207c +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_15 0x207e +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_0 0x2080 +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_1 0x2082 +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_2 0x2084 +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_3 0x2086 +#define CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_4 0x2088 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_5_0 0x20a0 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_5_1 0x20a2 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_5_2 0x20a4 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_5_3 0x20a6 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_5_4 0x20a8 +#define CORE_DIG_RW_TRIO0_0 0x2100 +#define CORE_DIG_RW_TRIO0_1 0x2102 +#define CORE_DIG_RW_TRIO0_2 0x2104 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_0 0x2400 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_1 0x2402 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_2 0x2404 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_3 0x2406 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_4 0x2408 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_5 0x240a +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_6 0x240c +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_7 0x240e +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_8 0x2410 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_9 0x2412 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_10 0x2414 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_11 0x2416 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_12 0x2418 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_13 0x241a +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_14 0x241c +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_15 0x241e +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_0 0x2420 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_1 0x2422 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_2 0x2424 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_3 0x2426 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_4 0x2428 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_5 0x242a +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_6 0x242c +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_7 0x242e +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_8 0x2430 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_9 0x2432 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_10 0x2434 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_11 0x2436 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_12 0x2438 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_13 0x243a +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_14 0x243c +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_15 0x243e +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_0 0x2440 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_1 0x2442 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2 0x2444 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_3 0x2446 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_4 0x2448 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_5 0x244a +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_6 0x244c +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_7 0x244e +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_8 0x2450 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9 0x2452 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_10 0x2454 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_11 0x2456 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_12 0x2458 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_13 0x245a +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_14 0x245c +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15 0x245e +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_0 0x2460 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_1 0x2462 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_2 0x2464 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_3 0x2466 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_4 0x2468 +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_5 0x246a +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_6 0x246c +#define CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_7 0x246e +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_8 0x2470 +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_9 0x2472 +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_10 0x2474 +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_11 0x2476 +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_12 0x2478 +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_13 0x247a +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_14 0x247c +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_15 0x247e +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_0 0x2480 +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_1 0x2482 +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_2 0x2484 +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_3 0x2486 +#define CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_4 0x2488 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_5_0 0x24a0 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_5_1 0x24a2 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_5_2 0x24a4 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_5_3 0x24a6 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_5_4 0x24a8 +#define CORE_DIG_RW_TRIO1_0 0x2500 +#define CORE_DIG_RW_TRIO1_1 0x2502 +#define CORE_DIG_RW_TRIO1_2 0x2504 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_0 0x2800 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_1 0x2802 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_2 0x2804 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_3 0x2806 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_4 0x2808 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_5 0x280a +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_6 0x280c +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_7 0x280e +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_8 0x2810 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_9 0x2812 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_10 0x2814 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_11 0x2816 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_12 0x2818 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_13 0x281a +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_14 0x281c +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_15 0x281e +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_0 0x2820 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_1 0x2822 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_2 0x2824 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_3 0x2826 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_4 0x2828 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_5 0x282a +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_6 0x282c +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_7 0x282e +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_8 0x2830 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_9 0x2832 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_10 0x2834 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_11 0x2836 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_12 0x2838 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_13 0x283a +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_14 0x283c +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_15 0x283e +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_0 0x2840 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_1 0x2842 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2 0x2844 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_3 0x2846 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_4 0x2848 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_5 0x284a +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_6 0x284c +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_7 0x284e +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_8 0x2850 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9 0x2852 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_10 0x2854 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_11 0x2856 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_12 0x2858 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_13 0x285a +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_14 0x285c +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15 0x285e +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_0 0x2860 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_1 0x2862 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_2 0x2864 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_3 0x2866 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_4 0x2868 +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_5 0x286a +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_6 0x286c +#define CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_7 0x286e +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_8 0x2870 +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_9 0x2872 +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_10 0x2874 +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_11 0x2876 +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_12 0x2878 +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_13 0x287a +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_14 0x287c +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_15 0x287e +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_0 0x2880 +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_1 0x2882 +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_2 0x2884 +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_3 0x2886 +#define CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_4 0x2888 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_5_0 0x28a0 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_5_1 0x28a2 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_5_2 0x28a4 +#define CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_5_3 0x28a6 +#define CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_5_4 0x28a8 +#define CORE_DIG_RW_TRIO2_0 0x2900 +#define CORE_DIG_RW_TRIO2_1 0x2902 +#define CORE_DIG_RW_TRIO2_2 0x2904 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_0 0x2c00 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_1 0x2c02 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_2 0x2c04 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_3 0x2c06 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_4 0x2c08 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_5 0x2c0a +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_6 0x2c0c +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_7 0x2c0e +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_8 0x2c10 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_9 0x2c12 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_10 0x2c14 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_11 0x2c16 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_12 0x2c18 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_13 0x2c1a +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_14 0x2c1c +#define CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_15 0x2c1e +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_0 0x2c40 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_1 0x2c42 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2 0x2c44 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_3 0x2c46 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_4 0x2c48 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_5 0x2c4a +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_6 0x2c4c +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_7 0x2c4e +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_8 0x2c50 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9 0x2c52 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_10 0x2c54 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_11 0x2c56 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_12 0x2c58 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_13 0x2c5a +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_14 0x2c5c +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_15 0x2c5e +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_0 0x2c60 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_1 0x2c62 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_2 0x2c64 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_3 0x2c66 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_4 0x2c68 +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_5 0x2c6a +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_6 0x2c6c +#define CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_7 0x2c6e +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_8 0x2c70 +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_9 0x2c72 +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_10 0x2c74 +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_11 0x2c76 +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_12 0x2c78 +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_13 0x2c7a +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_14 0x2c7c +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_15 0x2c7e +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_0 0x2c80 +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_1 0x2c82 +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_2 0x2c84 +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_3 0x2c86 +#define CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_4 0x2c88 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_0 0x3040 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_1 0x3042 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2 0x3044 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_3 0x3046 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_4 0x3048 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_5 0x304a +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_6 0x304c +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_7 0x304e +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_8 0x3050 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9 0x3052 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_10 0x3054 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_11 0x3056 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_12 0x3058 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_13 0x305a +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_14 0x305c +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_15 0x305e +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_0 0x3060 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_1 0x3062 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_2 0x3064 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_3 0x3066 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_4 0x3068 +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_5 0x306a +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_6 0x306c +#define CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_7 0x306e +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_8 0x3070 +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_9 0x3072 +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_10 0x3074 +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_11 0x3076 +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_12 0x3078 +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_13 0x307a +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_14 0x307c +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_15 0x307e +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_0 0x3080 +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_1 0x3082 +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_2 0x3084 +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_3 0x3086 +#define CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_4 0x3088 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_CLK_OVR_0_0 0x3400 +#define CORE_DIG_IOCTRL_RW_DPHY_PPI_CLK_OVR_0_1 0x3402 +#define CORE_DIG_IOCTRL_R_DPHY_PPI_CLK_OVR_0_2 0x3404 +#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_0 0x3800 +#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_1 0x3802 +#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_2 0x3804 +#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_3 0x3806 +#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_4 0x3808 +#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_5 0x380a +#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_6 0x380c +#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_7 0x380e +#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_8 0x3810 +#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_9 0x3812 +#define CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_10 0x3814 +#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_11 0x3816 +#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_12 0x3818 +#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_13 0x381a +#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_14 0x381c +#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_15 0x381e +#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_0 0x3820 +#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_1 0x3822 +#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_2 0x3824 +#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_3 0x3826 +#define CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_4 0x3828 +#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0 0x3840 +#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1 0x3842 +#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_2 0x3844 +#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_3 0x3846 +#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_4 0x3848 +#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_5 0x384a +#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_6 0x384c +#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7 0x384e +#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_8 0x3850 +#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_9 0x3852 +#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_10 0x3854 +#define CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_11 0x3856 +#define CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_12 0x3858 +#define CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_13 0x385a +#define CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_14 0x385c +#define CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_15 0x385e +#define CORE_DIG_IOCTRL_R_AFE_CB_CTRL_3_0 0x3860 +#define CORE_DIG_RW_COMMON_0 0x3880 +#define CORE_DIG_RW_COMMON_1 0x3882 +#define CORE_DIG_RW_COMMON_2 0x3884 +#define CORE_DIG_RW_COMMON_3 0x3886 +#define CORE_DIG_RW_COMMON_4 0x3888 +#define CORE_DIG_RW_COMMON_5 0x388a +#define CORE_DIG_RW_COMMON_6 0x388c +#define CORE_DIG_RW_COMMON_7 0x388e +#define CORE_DIG_RW_COMMON_8 0x3890 +#define CORE_DIG_RW_COMMON_9 0x3892 +#define CORE_DIG_RW_COMMON_10 0x3894 +#define CORE_DIG_RW_COMMON_11 0x3896 +#define CORE_DIG_RW_COMMON_12 0x3898 +#define CORE_DIG_RW_COMMON_13 0x389a +#define CORE_DIG_RW_COMMON_14 0x389c +#define CORE_DIG_RW_COMMON_15 0x389e +#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0 0x39e0 +#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_1 0x39e2 +#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2 0x39e4 +#define CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_3 0x39e6 +#define CORE_DIG_COMMON_RW_DESKEW_FINE_MEM 0x3fe0 +#define CORE_DIG_COMMON_R_DESKEW_FINE_MEM 0x3fe2 +#define PPI_RW_DPHY_LANE0_LBERT_0 0x4000 +#define PPI_RW_DPHY_LANE0_LBERT_1 0x4002 +#define PPI_R_DPHY_LANE0_LBERT_0 0x4004 +#define PPI_R_DPHY_LANE0_LBERT_1 0x4006 +#define PPI_RW_DPHY_LANE0_SPARE 0x4008 +#define PPI_RW_DPHY_LANE1_LBERT_0 0x4400 +#define PPI_RW_DPHY_LANE1_LBERT_1 0x4402 +#define PPI_R_DPHY_LANE1_LBERT_0 0x4404 +#define PPI_R_DPHY_LANE1_LBERT_1 0x4406 +#define PPI_RW_DPHY_LANE1_SPARE 0x4408 +#define PPI_RW_DPHY_LANE2_LBERT_0 0x4800 +#define PPI_RW_DPHY_LANE2_LBERT_1 0x4802 +#define PPI_R_DPHY_LANE2_LBERT_0 0x4804 +#define PPI_R_DPHY_LANE2_LBERT_1 0x4806 +#define PPI_RW_DPHY_LANE2_SPARE 0x4808 +#define PPI_RW_DPHY_LANE3_LBERT_0 0x4c00 +#define PPI_RW_DPHY_LANE3_LBERT_1 0x4c02 +#define PPI_R_DPHY_LANE3_LBERT_0 0x4c04 +#define PPI_R_DPHY_LANE3_LBERT_1 0x4c06 +#define PPI_RW_DPHY_LANE3_SPARE 0x4c08 +#define CORE_DIG_DLANE_0_RW_CFG_0 0x6000 +#define CORE_DIG_DLANE_0_RW_CFG_1 0x6002 +#define CORE_DIG_DLANE_0_RW_CFG_2 0x6004 +#define CORE_DIG_DLANE_0_RW_LP_0 0x6080 +#define CORE_DIG_DLANE_0_RW_LP_1 0x6082 +#define CORE_DIG_DLANE_0_RW_LP_2 0x6084 +#define CORE_DIG_DLANE_0_R_LP_0 0x60a0 +#define CORE_DIG_DLANE_0_R_LP_1 0x60a2 +#define CORE_DIG_DLANE_0_R_HS_TX_0 0x60e0 +#define CORE_DIG_DLANE_0_RW_HS_RX_0 0x6100 +#define CORE_DIG_DLANE_0_RW_HS_RX_1 0x6102 +#define CORE_DIG_DLANE_0_RW_HS_RX_2 0x6104 +#define CORE_DIG_DLANE_0_RW_HS_RX_3 0x6106 +#define CORE_DIG_DLANE_0_RW_HS_RX_4 0x6108 +#define CORE_DIG_DLANE_0_RW_HS_RX_5 0x610a +#define CORE_DIG_DLANE_0_RW_HS_RX_6 0x610c +#define CORE_DIG_DLANE_0_RW_HS_RX_7 0x610e +#define CORE_DIG_DLANE_0_RW_HS_RX_8 0x6110 +#define CORE_DIG_DLANE_0_RW_HS_RX_9 0x6112 +#define CORE_DIG_DLANE_0_R_HS_RX_0 0x6120 +#define CORE_DIG_DLANE_0_R_HS_RX_1 0x6122 +#define CORE_DIG_DLANE_0_R_HS_RX_2 0x6124 +#define CORE_DIG_DLANE_0_R_HS_RX_3 0x6126 +#define CORE_DIG_DLANE_0_R_HS_RX_4 0x6128 +#define CORE_DIG_DLANE_0_RW_HS_TX_0 0x6200 +#define CORE_DIG_DLANE_0_RW_HS_TX_1 0x6202 +#define CORE_DIG_DLANE_0_RW_HS_TX_2 0x6204 +#define CORE_DIG_DLANE_0_RW_HS_TX_3 0x6206 +#define CORE_DIG_DLANE_0_RW_HS_TX_4 0x6208 +#define CORE_DIG_DLANE_0_RW_HS_TX_5 0x620a +#define CORE_DIG_DLANE_0_RW_HS_TX_6 0x620c +#define CORE_DIG_DLANE_0_RW_HS_TX_7 0x620e +#define CORE_DIG_DLANE_0_RW_HS_TX_8 0x6210 +#define CORE_DIG_DLANE_0_RW_HS_TX_9 0x6212 +#define CORE_DIG_DLANE_0_RW_HS_TX_10 0x6214 +#define CORE_DIG_DLANE_0_RW_HS_TX_11 0x6216 +#define CORE_DIG_DLANE_0_RW_HS_TX_12 0x6218 +#define CORE_DIG_DLANE_1_RW_CFG_0 0x6400 +#define CORE_DIG_DLANE_1_RW_CFG_1 0x6402 +#define CORE_DIG_DLANE_1_RW_CFG_2 0x6404 +#define CORE_DIG_DLANE_1_RW_LP_0 0x6480 +#define CORE_DIG_DLANE_1_RW_LP_1 0x6482 +#define CORE_DIG_DLANE_1_RW_LP_2 0x6484 +#define CORE_DIG_DLANE_1_R_LP_0 0x64a0 +#define CORE_DIG_DLANE_1_R_LP_1 0x64a2 +#define CORE_DIG_DLANE_1_R_HS_TX_0 0x64e0 +#define CORE_DIG_DLANE_1_RW_HS_RX_0 0x6500 +#define CORE_DIG_DLANE_1_RW_HS_RX_1 0x6502 +#define CORE_DIG_DLANE_1_RW_HS_RX_2 0x6504 +#define CORE_DIG_DLANE_1_RW_HS_RX_3 0x6506 +#define CORE_DIG_DLANE_1_RW_HS_RX_4 0x6508 +#define CORE_DIG_DLANE_1_RW_HS_RX_5 0x650a +#define CORE_DIG_DLANE_1_RW_HS_RX_6 0x650c +#define CORE_DIG_DLANE_1_RW_HS_RX_7 0x650e +#define CORE_DIG_DLANE_1_RW_HS_RX_8 0x6510 +#define CORE_DIG_DLANE_1_RW_HS_RX_9 0x6512 +#define CORE_DIG_DLANE_1_R_HS_RX_0 0x6520 +#define CORE_DIG_DLANE_1_R_HS_RX_1 0x6522 +#define CORE_DIG_DLANE_1_R_HS_RX_2 0x6524 +#define CORE_DIG_DLANE_1_R_HS_RX_3 0x6526 +#define CORE_DIG_DLANE_1_R_HS_RX_4 0x6528 +#define CORE_DIG_DLANE_1_RW_HS_TX_0 0x6600 +#define CORE_DIG_DLANE_1_RW_HS_TX_1 0x6602 +#define CORE_DIG_DLANE_1_RW_HS_TX_2 0x6604 +#define CORE_DIG_DLANE_1_RW_HS_TX_3 0x6606 +#define CORE_DIG_DLANE_1_RW_HS_TX_4 0x6608 +#define CORE_DIG_DLANE_1_RW_HS_TX_5 0x660a +#define CORE_DIG_DLANE_1_RW_HS_TX_6 0x660c +#define CORE_DIG_DLANE_1_RW_HS_TX_7 0x660e +#define CORE_DIG_DLANE_1_RW_HS_TX_8 0x6610 +#define CORE_DIG_DLANE_1_RW_HS_TX_9 0x6612 +#define CORE_DIG_DLANE_1_RW_HS_TX_10 0x6614 +#define CORE_DIG_DLANE_1_RW_HS_TX_11 0x6616 +#define CORE_DIG_DLANE_1_RW_HS_TX_12 0x6618 +#define CORE_DIG_DLANE_2_RW_CFG_0 0x6800 +#define CORE_DIG_DLANE_2_RW_CFG_1 0x6802 +#define CORE_DIG_DLANE_2_RW_CFG_2 0x6804 +#define CORE_DIG_DLANE_2_RW_LP_0 0x6880 +#define CORE_DIG_DLANE_2_RW_LP_1 0x6882 +#define CORE_DIG_DLANE_2_RW_LP_2 0x6884 +#define CORE_DIG_DLANE_2_R_LP_0 0x68a0 +#define CORE_DIG_DLANE_2_R_LP_1 0x68a2 +#define CORE_DIG_DLANE_2_R_HS_TX_0 0x68e0 +#define CORE_DIG_DLANE_2_RW_HS_RX_0 0x6900 +#define CORE_DIG_DLANE_2_RW_HS_RX_1 0x6902 +#define CORE_DIG_DLANE_2_RW_HS_RX_2 0x6904 +#define CORE_DIG_DLANE_2_RW_HS_RX_3 0x6906 +#define CORE_DIG_DLANE_2_RW_HS_RX_4 0x6908 +#define CORE_DIG_DLANE_2_RW_HS_RX_5 0x690a +#define CORE_DIG_DLANE_2_RW_HS_RX_6 0x690c +#define CORE_DIG_DLANE_2_RW_HS_RX_7 0x690e +#define CORE_DIG_DLANE_2_RW_HS_RX_8 0x6910 +#define CORE_DIG_DLANE_2_RW_HS_RX_9 0x6912 +#define CORE_DIG_DLANE_2_R_HS_RX_0 0x6920 +#define CORE_DIG_DLANE_2_R_HS_RX_1 0x6922 +#define CORE_DIG_DLANE_2_R_HS_RX_2 0x6924 +#define CORE_DIG_DLANE_2_R_HS_RX_3 0x6926 +#define CORE_DIG_DLANE_2_R_HS_RX_4 0x6928 +#define CORE_DIG_DLANE_2_RW_HS_TX_0 0x6a00 +#define CORE_DIG_DLANE_2_RW_HS_TX_1 0x6a02 +#define CORE_DIG_DLANE_2_RW_HS_TX_2 0x6a04 +#define CORE_DIG_DLANE_2_RW_HS_TX_3 0x6a06 +#define CORE_DIG_DLANE_2_RW_HS_TX_4 0x6a08 +#define CORE_DIG_DLANE_2_RW_HS_TX_5 0x6a0a +#define CORE_DIG_DLANE_2_RW_HS_TX_6 0x6a0c +#define CORE_DIG_DLANE_2_RW_HS_TX_7 0x6a0e +#define CORE_DIG_DLANE_2_RW_HS_TX_8 0x6a10 +#define CORE_DIG_DLANE_2_RW_HS_TX_9 0x6a12 +#define CORE_DIG_DLANE_2_RW_HS_TX_10 0x6a14 +#define CORE_DIG_DLANE_2_RW_HS_TX_11 0x6a16 +#define CORE_DIG_DLANE_2_RW_HS_TX_12 0x6a18 +#define CORE_DIG_DLANE_3_RW_CFG_0 0x6c00 +#define CORE_DIG_DLANE_3_RW_CFG_1 0x6c02 +#define CORE_DIG_DLANE_3_RW_CFG_2 0x6c04 +#define CORE_DIG_DLANE_3_RW_LP_0 0x6c80 +#define CORE_DIG_DLANE_3_RW_LP_1 0x6c82 +#define CORE_DIG_DLANE_3_RW_LP_2 0x6c84 +#define CORE_DIG_DLANE_3_R_LP_0 0x6ca0 +#define CORE_DIG_DLANE_3_R_LP_1 0x6ca2 +#define CORE_DIG_DLANE_3_R_HS_TX_0 0x6ce0 +#define CORE_DIG_DLANE_3_RW_HS_RX_0 0x6d00 +#define CORE_DIG_DLANE_3_RW_HS_RX_1 0x6d02 +#define CORE_DIG_DLANE_3_RW_HS_RX_2 0x6d04 +#define CORE_DIG_DLANE_3_RW_HS_RX_3 0x6d06 +#define CORE_DIG_DLANE_3_RW_HS_RX_4 0x6d08 +#define CORE_DIG_DLANE_3_RW_HS_RX_5 0x6d0a +#define CORE_DIG_DLANE_3_RW_HS_RX_6 0x6d0c +#define CORE_DIG_DLANE_3_RW_HS_RX_7 0x6d0e +#define CORE_DIG_DLANE_3_RW_HS_RX_8 0x6d10 +#define CORE_DIG_DLANE_3_RW_HS_RX_9 0x6d12 +#define CORE_DIG_DLANE_3_R_HS_RX_0 0x6d20 +#define CORE_DIG_DLANE_3_R_HS_RX_1 0x6d22 +#define CORE_DIG_DLANE_3_R_HS_RX_2 0x6d24 +#define CORE_DIG_DLANE_3_R_HS_RX_3 0x6d26 +#define CORE_DIG_DLANE_3_R_HS_RX_4 0x6d28 +#define CORE_DIG_DLANE_3_RW_HS_TX_0 0x6e00 +#define CORE_DIG_DLANE_3_RW_HS_TX_1 0x6e02 +#define CORE_DIG_DLANE_3_RW_HS_TX_2 0x6e04 +#define CORE_DIG_DLANE_3_RW_HS_TX_3 0x6e06 +#define CORE_DIG_DLANE_3_RW_HS_TX_4 0x6e08 +#define CORE_DIG_DLANE_3_RW_HS_TX_5 0x6e0a +#define CORE_DIG_DLANE_3_RW_HS_TX_6 0x6e0c +#define CORE_DIG_DLANE_3_RW_HS_TX_7 0x6e0e +#define CORE_DIG_DLANE_3_RW_HS_TX_8 0x6e10 +#define CORE_DIG_DLANE_3_RW_HS_TX_9 0x6e12 +#define CORE_DIG_DLANE_3_RW_HS_TX_10 0x6e14 +#define CORE_DIG_DLANE_3_RW_HS_TX_11 0x6e16 +#define CORE_DIG_DLANE_3_RW_HS_TX_12 0x6e18 +#define CORE_DIG_DLANE_CLK_RW_CFG_0 0x7000 +#define CORE_DIG_DLANE_CLK_RW_CFG_1 0x7002 +#define CORE_DIG_DLANE_CLK_RW_CFG_2 0x7004 +#define CORE_DIG_DLANE_CLK_RW_LP_0 0x7080 +#define CORE_DIG_DLANE_CLK_RW_LP_1 0x7082 +#define CORE_DIG_DLANE_CLK_RW_LP_2 0x7084 +#define CORE_DIG_DLANE_CLK_R_LP_0 0x70a0 +#define CORE_DIG_DLANE_CLK_R_LP_1 0x70a2 +#define CORE_DIG_DLANE_CLK_R_HS_TX_0 0x70e0 +#define CORE_DIG_DLANE_CLK_RW_HS_RX_0 0x7100 +#define CORE_DIG_DLANE_CLK_RW_HS_RX_1 0x7102 +#define CORE_DIG_DLANE_CLK_RW_HS_RX_2 0x7104 +#define CORE_DIG_DLANE_CLK_RW_HS_RX_3 0x7106 +#define CORE_DIG_DLANE_CLK_RW_HS_RX_4 0x7108 +#define CORE_DIG_DLANE_CLK_RW_HS_RX_5 0x710a +#define CORE_DIG_DLANE_CLK_RW_HS_RX_6 0x710c +#define CORE_DIG_DLANE_CLK_RW_HS_RX_7 0x710e +#define CORE_DIG_DLANE_CLK_RW_HS_RX_8 0x7110 +#define CORE_DIG_DLANE_CLK_RW_HS_RX_9 0x7112 +#define CORE_DIG_DLANE_CLK_R_HS_RX_0 0x7120 +#define CORE_DIG_DLANE_CLK_R_HS_RX_1 0x7122 +#define CORE_DIG_DLANE_CLK_R_HS_RX_2 0x7124 +#define CORE_DIG_DLANE_CLK_R_HS_RX_3 0x7126 +#define CORE_DIG_DLANE_CLK_R_HS_RX_4 0x7128 +#define CORE_DIG_DLANE_CLK_RW_HS_TX_0 0x7200 +#define CORE_DIG_DLANE_CLK_RW_HS_TX_1 0x7202 +#define CORE_DIG_DLANE_CLK_RW_HS_TX_2 0x7204 +#define CORE_DIG_DLANE_CLK_RW_HS_TX_3 0x7206 +#define CORE_DIG_DLANE_CLK_RW_HS_TX_4 0x7208 +#define CORE_DIG_DLANE_CLK_RW_HS_TX_5 0x720a +#define CORE_DIG_DLANE_CLK_RW_HS_TX_6 0x720c +#define CORE_DIG_DLANE_CLK_RW_HS_TX_7 0x720e +#define CORE_DIG_DLANE_CLK_RW_HS_TX_8 0x7210 +#define CORE_DIG_DLANE_CLK_RW_HS_TX_9 0x7212 +#define CORE_DIG_DLANE_CLK_RW_HS_TX_10 0x7214 +#define CORE_DIG_DLANE_CLK_RW_HS_TX_11 0x7216 +#define CORE_DIG_DLANE_CLK_RW_HS_TX_12 0x7218 +#define PPI_RW_CPHY_TRIO0_LBERT_0 0x8000 +#define PPI_RW_CPHY_TRIO0_LBERT_1 0x8002 +#define PPI_R_CPHY_TRIO0_LBERT_0 0x8004 +#define PPI_R_CPHY_TRIO0_LBERT_1 0x8006 +#define PPI_RW_CPHY_TRIO0_SPARE 0x8008 +#define PPI_RW_CPHY_TRIO1_LBERT_0 0x8400 +#define PPI_RW_CPHY_TRIO1_LBERT_1 0x8402 +#define PPI_R_CPHY_TRIO1_LBERT_0 0x8404 +#define PPI_R_CPHY_TRIO1_LBERT_1 0x8406 +#define PPI_RW_CPHY_TRIO1_SPARE 0x8408 +#define PPI_RW_CPHY_TRIO2_LBERT_0 0x8800 +#define PPI_RW_CPHY_TRIO2_LBERT_1 0x8802 +#define PPI_R_CPHY_TRIO2_LBERT_0 0x8804 +#define PPI_R_CPHY_TRIO2_LBERT_1 0x8806 +#define PPI_RW_CPHY_TRIO2_SPARE 0x8808 +#define CORE_DIG_CLANE_0_RW_CFG_0 0xa000 +#define CORE_DIG_CLANE_0_RW_CFG_2 0xa004 +#define CORE_DIG_CLANE_0_RW_LP_0 0xa080 +#define CORE_DIG_CLANE_0_RW_LP_1 0xa082 +#define CORE_DIG_CLANE_0_RW_LP_2 0xa084 +#define CORE_DIG_CLANE_0_R_LP_0 0xa0a0 +#define CORE_DIG_CLANE_0_R_LP_1 0xa0a2 +#define CORE_DIG_CLANE_0_RW_HS_RX_0 0xa100 +#define CORE_DIG_CLANE_0_RW_HS_RX_1 0xa102 +#define CORE_DIG_CLANE_0_RW_HS_RX_2 0xa104 +#define CORE_DIG_CLANE_0_RW_HS_RX_3 0xa106 +#define CORE_DIG_CLANE_0_RW_HS_RX_4 0xa108 +#define CORE_DIG_CLANE_0_RW_HS_RX_5 0xa10a +#define CORE_DIG_CLANE_0_RW_HS_RX_6 0xa10c +#define CORE_DIG_CLANE_0_R_RX_0 0xa120 +#define CORE_DIG_CLANE_0_R_RX_1 0xa122 +#define CORE_DIG_CLANE_0_R_TX_0 0xa124 +#define CORE_DIG_CLANE_0_R_RX_2 0xa126 +#define CORE_DIG_CLANE_0_R_RX_3 0xa128 +#define CORE_DIG_CLANE_0_RW_HS_TX_0 0xa200 +#define CORE_DIG_CLANE_0_RW_HS_TX_1 0xa202 +#define CORE_DIG_CLANE_0_RW_HS_TX_2 0xa204 +#define CORE_DIG_CLANE_0_RW_HS_TX_3 0xa206 +#define CORE_DIG_CLANE_0_RW_HS_TX_4 0xa208 +#define CORE_DIG_CLANE_0_RW_HS_TX_5 0xa20a +#define CORE_DIG_CLANE_0_RW_HS_TX_6 0xa20c +#define CORE_DIG_CLANE_0_RW_HS_TX_7 0xa20e +#define CORE_DIG_CLANE_0_RW_HS_TX_8 0xa210 +#define CORE_DIG_CLANE_0_RW_HS_TX_9 0xa212 +#define CORE_DIG_CLANE_0_RW_HS_TX_10 0xa214 +#define CORE_DIG_CLANE_0_RW_HS_TX_11 0xa216 +#define CORE_DIG_CLANE_0_RW_HS_TX_12 0xa218 +#define CORE_DIG_CLANE_0_RW_HS_TX_13 0xa21a +#define CORE_DIG_CLANE_1_RW_CFG_0 0xa400 +#define CORE_DIG_CLANE_1_RW_CFG_2 0xa404 +#define CORE_DIG_CLANE_1_RW_LP_0 0xa480 +#define CORE_DIG_CLANE_1_RW_LP_1 0xa482 +#define CORE_DIG_CLANE_1_RW_LP_2 0xa484 +#define CORE_DIG_CLANE_1_R_LP_0 0xa4a0 +#define CORE_DIG_CLANE_1_R_LP_1 0xa4a2 +#define CORE_DIG_CLANE_1_RW_HS_RX_0 0xa500 +#define CORE_DIG_CLANE_1_RW_HS_RX_1 0xa502 +#define CORE_DIG_CLANE_1_RW_HS_RX_2 0xa504 +#define CORE_DIG_CLANE_1_RW_HS_RX_3 0xa506 +#define CORE_DIG_CLANE_1_RW_HS_RX_4 0xa508 +#define CORE_DIG_CLANE_1_RW_HS_RX_5 0xa50a +#define CORE_DIG_CLANE_1_RW_HS_RX_6 0xa50c +#define CORE_DIG_CLANE_1_R_RX_0 0xa520 +#define CORE_DIG_CLANE_1_R_RX_1 0xa522 +#define CORE_DIG_CLANE_1_R_TX_0 0xa524 +#define CORE_DIG_CLANE_1_R_RX_2 0xa526 +#define CORE_DIG_CLANE_1_R_RX_3 0xa528 +#define CORE_DIG_CLANE_1_RW_HS_TX_0 0xa600 +#define CORE_DIG_CLANE_1_RW_HS_TX_1 0xa602 +#define CORE_DIG_CLANE_1_RW_HS_TX_2 0xa604 +#define CORE_DIG_CLANE_1_RW_HS_TX_3 0xa606 +#define CORE_DIG_CLANE_1_RW_HS_TX_4 0xa608 +#define CORE_DIG_CLANE_1_RW_HS_TX_5 0xa60a +#define CORE_DIG_CLANE_1_RW_HS_TX_6 0xa60c +#define CORE_DIG_CLANE_1_RW_HS_TX_7 0xa60e +#define CORE_DIG_CLANE_1_RW_HS_TX_8 0xa610 +#define CORE_DIG_CLANE_1_RW_HS_TX_9 0xa612 +#define CORE_DIG_CLANE_1_RW_HS_TX_10 0xa614 +#define CORE_DIG_CLANE_1_RW_HS_TX_11 0xa616 +#define CORE_DIG_CLANE_1_RW_HS_TX_12 0xa618 +#define CORE_DIG_CLANE_1_RW_HS_TX_13 0xa61a +#define CORE_DIG_CLANE_2_RW_CFG_0 0xa800 +#define CORE_DIG_CLANE_2_RW_CFG_2 0xa804 +#define CORE_DIG_CLANE_2_RW_LP_0 0xa880 +#define CORE_DIG_CLANE_2_RW_LP_1 0xa882 +#define CORE_DIG_CLANE_2_RW_LP_2 0xa884 +#define CORE_DIG_CLANE_2_R_LP_0 0xa8a0 +#define CORE_DIG_CLANE_2_R_LP_1 0xa8a2 +#define CORE_DIG_CLANE_2_RW_HS_RX_0 0xa900 +#define CORE_DIG_CLANE_2_RW_HS_RX_1 0xa902 +#define CORE_DIG_CLANE_2_RW_HS_RX_2 0xa904 +#define CORE_DIG_CLANE_2_RW_HS_RX_3 0xa906 +#define CORE_DIG_CLANE_2_RW_HS_RX_4 0xa908 +#define CORE_DIG_CLANE_2_RW_HS_RX_5 0xa90a +#define CORE_DIG_CLANE_2_RW_HS_RX_6 0xa90c +#define CORE_DIG_CLANE_2_R_RX_0 0xa920 +#define CORE_DIG_CLANE_2_R_RX_1 0xa922 +#define CORE_DIG_CLANE_2_R_TX_0 0xa924 +#define CORE_DIG_CLANE_2_R_RX_2 0xa926 +#define CORE_DIG_CLANE_2_R_RX_3 0xa928 +#define CORE_DIG_CLANE_2_RW_HS_TX_0 0xaa00 +#define CORE_DIG_CLANE_2_RW_HS_TX_1 0xaa02 +#define CORE_DIG_CLANE_2_RW_HS_TX_2 0xaa04 +#define CORE_DIG_CLANE_2_RW_HS_TX_3 0xaa06 +#define CORE_DIG_CLANE_2_RW_HS_TX_4 0xaa08 +#define CORE_DIG_CLANE_2_RW_HS_TX_5 0xaa0a +#define CORE_DIG_CLANE_2_RW_HS_TX_6 0xaa0c +#define CORE_DIG_CLANE_2_RW_HS_TX_7 0xaa0e +#define CORE_DIG_CLANE_2_RW_HS_TX_8 0xaa10 +#define CORE_DIG_CLANE_2_RW_HS_TX_9 0xaa12 +#define CORE_DIG_CLANE_2_RW_HS_TX_10 0xaa14 +#define CORE_DIG_CLANE_2_RW_HS_TX_11 0xaa16 +#define CORE_DIG_CLANE_2_RW_HS_TX_12 0xaa18 +#define CORE_DIG_CLANE_2_RW_HS_TX_13 0xaa1a + +/* dwc csi host controller registers */ +#define IS_IO_CSI2_HOST_BASE(i) (IS_IO_BASE + 0x40000 + \ + 0x2000 * (i)) +#define VERSION 0x0 +#define N_LANES 0x4 +#define CSI2_RESETN 0x8 +#define INT_ST_MAIN 0xc +#define DATA_IDS_1 0x10 +#define DATA_IDS_2 0x14 +#define CDPHY_MODE 0x1c +#define DATA_IDS_VC_1 0x30 +#define DATA_IDS_VC_2 0x34 +#define PHY_SHUTDOWNZ 0x40 +#define DPHY_RSTZ 0x44 +#define PHY_RX 0x48 +#define PHY_STOPSTATE 0x4c +#define PHY_TEST_CTRL0 0x50 +#define PHY_TEST_CTRL1 0x54 +#define PPI_PG_PATTERN_VRES 0x60 +#define PPI_PG_PATTERN_HRES 0x64 +#define PPI_PG_CONFIG 0x68 +#define PPI_PG_ENABLE 0x6c +#define PPI_PG_STATUS 0x70 +#define VC_EXTENSION 0xc8 +#define PHY_CAL 0xcc +#define INT_ST_PHY_FATAL 0xe0 +#define INT_MSK_PHY_FATAL 0xe4 +#define INT_FORCE_PHY_FATAL 0xe8 +#define INT_ST_PKT_FATAL 0xf0 +#define INT_MSK_PKT_FATAL 0xf4 +#define INT_FORCE_PKT_FATAL 0xf8 +#define INT_ST_PHY 0x110 +#define INT_MSK_PHY 0x114 +#define INT_FORCE_PHY 0x118 +#define INT_ST_LINE 0x130 +#define INT_MSK_LINE 0x134 +#define INT_FORCE_LINE 0x138 +#define INT_ST_BNDRY_FRAME_FATAL 0x280 +#define INT_MSK_BNDRY_FRAME_FATAL 0x284 +#define INT_FORCE_BNDRY_FRAME_FATAL 0x288 +#define INT_ST_SEQ_FRAME_FATAL 0x290 +#define INT_MSK_SEQ_FRAME_FATAL 0x294 +#define INT_FORCE_SEQ_FRAME_FATAL 0x298 +#define INT_ST_CRC_FRAME_FATAL 0x2a0 +#define INT_MSK_CRC_FRAME_FATAL 0x2a4 +#define INT_FORCE_CRC_FRAME_FATAL 0x2a8 +#define INT_ST_PLD_CRC_FATAL 0x2b0 +#define INT_MSK_PLD_CRC_FATAL 0x2b4 +#define INT_FORCE_PLD_CRC_FATAL 0x2b8 +#define INT_ST_DATA_ID 0x2c0 +#define INT_MSK_DATA_ID 0x2c4 +#define INT_FORCE_DATA_ID 0x2c8 +#define INT_ST_ECC_CORRECTED 0x2d0 +#define INT_MSK_ECC_CORRECTED 0x2d4 +#define INT_FORCE_ECC_CORRECTED 0x2d8 +#define SCRAMBLING 0x300 +#define SCRAMBLING_SEED1 0x304 +#define SCRAMBLING_SEED2 0x308 +#define SCRAMBLING_SEED3 0x30c +#define SCRAMBLING_SEED4 0x310 +#define SCRAMBLING 0x300 + +#define IS_IO_CSI2_ADPL_PORT_BASE(i) (IS_IO_BASE + 0x40800 + \ + 0x2000 * (i)) +#define CSI2_ADPL_INPUT_MODE 0x0 +#define CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_EN 0x4 +#define CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_ADDR 0x8 +#define CSI2_ADPL_CSI_RX_ERR_IRQ_STATUS 0xc +#define CSI2_ADPL_IRQ_CTL_COMMON_STATUS 0xa4 +#define CSI2_ADPL_IRQ_CTL_COMMON_CLEAR 0xa8 +#define CSI2_ADPL_IRQ_CTL_COMMON_ENABLE 0xac +#define CSI2_ADPL_IRQ_CTL_FS_STATUS 0xbc +#define CSI2_ADPL_IRQ_CTL_FS_CLEAR 0xc0 +#define CSI2_ADPL_IRQ_CTL_FS_ENABLE 0xc4 +#define CSI2_ADPL_IRQ_CTL_FE_STATUS 0xc8 +#define CSI2_ADPL_IRQ_CTL_FE_CLEAR 0xcc +#define CSI2_ADPL_IRQ_CTL_FE_ENABLE 0xd0 + +/* software control the legacy csi irq */ +#define IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(i) (IS_IO_BASE + 0x40c00 + \ + 0x2000 * (i)) +#define IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(i) (IS_IO_BASE + 0x40d00 + \ + 0x2000 * (i)) +#define IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE (IS_IO_BASE + 0x49000) +#define IS_IO_CSI2_IRQ_CTRL_BASE (IS_IO_BASE + 0x4e100) + +#define IRQ_CTL_EDGE 0x0 +#define IRQ_CTL_MASK 0x4 +#define IRQ_CTL_STATUS 0x8 +#define IRQ_CTL_CLEAR 0xc +#define IRQ_CTL_ENABLE 0x10 +/* FE irq for PTL */ +#define IRQ1_CTL_MASK 0x14 +#define IRQ1_CTL_STATUS 0x18 +#define IRQ1_CTL_CLEAR 0x1c +#define IRQ1_CTL_ENABLE 0x20 + +/* software to set the clock gate to use the port or mgc */ +#define IS_IO_GPREGS_BASE (IS_IO_BASE + 0x49200) +#define SRST_PORT_ARB 0x0 +#define SRST_MGC 0x4 +#define SRST_WIDTH_CONV 0x8 +#define SRST_CSI_IRQ 0xc +#define SRST_CSI_LEGACY_IRQ 0x10 +#define CLK_EN_TXCLKESC 0x14 +#define CLK_DIV_FACTOR_IS_CLK 0x18 +#define CLK_DIV_FACTOR_APB_CLK 0x1c +#define CSI_PORT_CLK_GATE 0x20 +#define CSI_PORTAB_AGGREGATION 0x24 +#define MGC_CLK_GATE 0x2c +#define CG_CTRL_BITS 0x3c +#define SPARE_RW 0xf8 +#define SPARE_RO 0xfc + +#define IS_IO_CSI2_MPF_PORT_BASE(i) (IS_IO_BASE + 0x53000 + \ + 0x1000 * (i)) +#define MPF_16_IRQ_CNTRL_STATUS 0x238 +#define MPF_16_IRQ_CNTRL_CLEAR 0x23c +#define MPF_16_IRQ_CNTRL_ENABLE 0x240 + +/* software config the phy */ +#define IS_IO_CSI2_GPREGS_BASE (IS_IO_BASE + 0x53400) +#define IPU8_IS_IO_CSI2_GPREGS_BASE (IS_IO_BASE + 0x40e00) +#define CSI_ADAPT_LAYER_SRST 0x0 +#define MPF_SRST_RST 0x4 +#define CSI_ERR_IRQ_CTRL_SRST 0x8 +#define CSI_SYNC_RC_SRST 0xc +#define CSI_CG_CTRL_BITS 0x10 +#define SOC_CSI2HOST_SELECT 0x14 +#define PHY_RESET 0x18 +#define PHY_SHUTDOWN 0x1c +#define PHY_MODE 0x20 +#define PHY_READY 0x24 +#define PHY_CLK_LANE_FORCE_CONTROL 0x28 +#define PHY_CLK_LANE_CONTROL 0x2c +#define PHY_CLK_LANE_STATUS 0x30 +#define PHY_LANE_RX_ESC_REQ 0x34 +#define PHY_LANE_RX_ESC_DATA 0x38 +#define PHY_LANE_TURNDISABLE 0x3c +#define PHY_LANE_DIRECTION 0x40 +#define PHY_LANE_FORCE_CONTROL 0x44 +#define PHY_LANE_CONTROL_EN 0x48 +#define PHY_LANE_CONTROL_DATAWIDTH 0x4c +#define PHY_LANE_STATUS 0x50 +#define PHY_LANE_ERR 0x54 +#define PHY_LANE_RXALP 0x58 +#define PHY_LANE_RXALP_NIBBLE 0x5c +#define PHY_PARITY_ERROR 0x60 +#define PHY_DEBUG_REGS_CLK_GATE_EN 0x64 +#define SPARE_RW 0xf8 +#define SPARE_RO 0xfc + +/* software not touch */ +#define PORT_ARB_BASE (IS_IO_BASE + 0x4e000) +#define PORT_ARB_IRQ_CTL_STATUS 0x4 +#define PORT_ARB_IRQ_CTL_CLEAR 0x8 +#define PORT_ARB_IRQ_CTL_ENABLE 0xc + +#define MGC_PPC 4U +#define MGC_DTYPE_RAW(i) (((i) - 8) / 2) +#define IS_IO_MGC_BASE (IS_IO_BASE + 0x48000) +#define MGC_KICK 0x0 +#define MGC_ASYNC_STOP 0x4 +#define MGC_PORT_OFFSET 0x100 +#define MGC_CSI_PORT_MAP(i) (0x8 + (i) * 0x4) +#define MGC_MG_PORT(i) (IS_IO_MGC_BASE + \ + (i) * MGC_PORT_OFFSET) +/* per mgc instance */ +#define MGC_MG_CSI_ADAPT_LAYER_TYPE 0x28 +#define MGC_MG_MODE 0x2c +#define MGC_MG_INIT_COUNTER 0x30 +#define MGC_MG_MIPI_VC 0x34 +#define MGC_MG_MIPI_DTYPES 0x38 +#define MGC_MG_MULTI_DTYPES_MODE 0x3c +#define MGC_MG_NOF_FRAMES 0x40 +#define MGC_MG_FRAME_DIM 0x44 +#define MGC_MG_HBLANK 0x48 +#define MGC_MG_VBLANK 0x4c +#define MGC_MG_TPG_MODE 0x50 +#define MGC_MG_TPG_R0 0x54 +#define MGC_MG_TPG_G0 0x58 +#define MGC_MG_TPG_B0 0x5c +#define MGC_MG_TPG_R1 0x60 +#define MGC_MG_TPG_G1 0x64 +#define MGC_MG_TPG_B1 0x68 +#define MGC_MG_TPG_FACTORS 0x6c +#define MGC_MG_TPG_MASKS 0x70 +#define MGC_MG_TPG_XY_MASK 0x74 +#define MGC_MG_TPG_TILE_DIM 0x78 +#define MGC_MG_PRBS_LFSR_INIT_0 0x7c +#define MGC_MG_PRBS_LFSR_INIT_1 0x80 +#define MGC_MG_SYNC_STOP_POINT 0x84 +#define MGC_MG_SYNC_STOP_POINT_LOC 0x88 +#define MGC_MG_ERR_INJECT 0x8c +#define MGC_MG_ERR_LOCATION 0x90 +#define MGC_MG_DTO_SPEED_CTRL_EN 0x94 +#define MGC_MG_DTO_SPEED_CTRL_INCR_VAL 0x98 +#define MGC_MG_HOR_LOC_STTS 0x9c +#define MGC_MG_VER_LOC_STTS 0xa0 +#define MGC_MG_FRAME_NUM_STTS 0xa4 +#define MGC_MG_BUSY_STTS 0xa8 +#define MGC_MG_STOPPED_STTS 0xac +/* tile width and height in pixels for Chess board and Color palette */ +#define MGC_TPG_TILE_WIDTH 64U +#define MGC_TPG_TILE_HEIGHT 64U + +#define IPU_CSI_PORT_A_ADDR_OFFSET 0x0 +#define IPU_CSI_PORT_B_ADDR_OFFSET 0x0 +#define IPU_CSI_PORT_C_ADDR_OFFSET 0x0 +#define IPU_CSI_PORT_D_ADDR_OFFSET 0x0 + +/* + * 0 - CSI RX Port 0 interrupt; + * 1 - MPF Port 0 interrupt; + * 2 - CSI RX Port 1 interrupt; + * 3 - MPF Port 1 interrupt; + * 4 - CSI RX Port 2 interrupt; + * 5 - MPF Port 2 interrupt; + * 6 - CSI RX Port 3 interrupt; + * 7 - MPF Port 3 interrupt; + * 8 - Port ARB FIFO 0 overflow; + * 9 - Port ARB FIFO 1 overflow; + * 10 - Port ARB FIFO 2 overflow; + * 11 - Port ARB FIFO 3 overflow; + * 12 - isys_cfgnoc_err_probe_intl; + * 13-15 - reserved + */ +#define IPU7_CSI_IS_IO_IRQ_MASK 0xffff + +/* Adapter layer irq */ +#define IPU7_CSI_ADPL_IRQ_MASK 0xffff + +/* sw irq from legacy irq control + * legacy irq status + * IPU7 + * 0 - CSI Port 0 error interrupt + * 1 - CSI Port 0 sync interrupt + * 2 - CSI Port 1 error interrupt + * 3 - CSI Port 1 sync interrupt + * 4 - CSI Port 2 error interrupt + * 5 - CSI Port 2 sync interrupt + * 6 - CSI Port 3 error interrupt + * 7 - CSI Port 3 sync interrupt + * IPU7P5 + * 0 - CSI Port 0 error interrupt + * 1 - CSI Port 0 fs interrupt + * 2 - CSI Port 0 fe interrupt + * 3 - CSI Port 1 error interrupt + * 4 - CSI Port 1 fs interrupt + * 5 - CSI Port 1 fe interrupt + * 6 - CSI Port 2 error interrupt + * 7 - CSI Port 2 fs interrupt + * 8 - CSI Port 2 fe interrupt + */ +#define IPU7_CSI_RX_LEGACY_IRQ_MASK 0x1ff + +/* legacy error status per port + * 0 - Error handler FIFO full; + * 1 - Reserved Short Packet encoding detected; + * 2 - Reserved Long Packet encoding detected; + * 3 - Received packet is too short (fewer data words than specified in header); + * 4 - Received packet is too long (more data words than specified in header); + * 5 - Short packet discarded due to errors; + * 6 - Long packet discarded due to errors; + * 7 - CSI Combo Rx interrupt; + * 8 - IDI CDC FIFO overflow; remaining bits are reserved and tied to 0; + */ +#define IPU7_CSI_RX_ERROR_IRQ_MASK 0xfff + +/* + * 0 - VC0 frame start received + * 1 - VC0 frame end received + * 2 - VC1 frame start received + * 3 - VC1 frame end received + * 4 - VC2 frame start received + * 5 - VC2 frame end received + * 6 - VC3 frame start received + * 7 - VC3 frame end received + * 8 - VC4 frame start received + * 9 - VC4 frame end received + * 10 - VC5 frame start received + * 11 - VC5 frame end received + * 12 - VC6 frame start received + * 13 - VC6 frame end received + * 14 - VC7 frame start received + * 15 - VC7 frame end received + * 16 - VC8 frame start received + * 17 - VC8 frame end received + * 18 - VC9 frame start received + * 19 - VC9 frame end received + * 20 - VC10 frame start received + * 21 - VC10 frame end received + * 22 - VC11 frame start received + * 23 - VC11 frame end received + * 24 - VC12 frame start received + * 25 - VC12 frame end received + * 26 - VC13 frame start received + * 27 - VC13 frame end received + * 28 - VC14 frame start received + * 29 - VC14 frame end received + * 30 - VC15 frame start received + * 31 - VC15 frame end received + */ + +#define IPU7_CSI_RX_SYNC_IRQ_MASK 0x0 +#define IPU7P5_CSI_RX_SYNC_FE_IRQ_MASK 0x0 + +#define CSI_RX_NUM_ERRORS_IN_IRQ 12U +#define CSI_RX_NUM_SYNC_IN_IRQ 32U + +enum CSI_FE_MODE_TYPE { + CSI_FE_DPHY_MODE = 0, + CSI_FE_CPHY_MODE = 1, +}; + +enum CSI_FE_INPUT_MODE { + CSI_SENSOR_INPUT = 0, + CSI_MIPIGEN_INPUT = 1, +}; + +enum MGC_CSI_ADPL_TYPE { + MGC_MAPPED_2_LANES = 0, + MGC_MAPPED_4_LANES = 1, +}; + +enum CSI2HOST_SELECTION { + CSI2HOST_SEL_SOC = 0, + CSI2HOST_SEL_CSI2HOST = 1, +}; + +#define IPU7_ISYS_LEGACY_IRQ_CSI2(port) (0x3 << (port)) +#define IPU7P5_ISYS_LEGACY_IRQ_CSI2(port) (0x7 << (port)) + +/* ---------------------------------------------------------------- */ +#define CSI_REG_BASE 0x220000 +#define CSI_REG_BASE_PORT(id) ((id) * 0x1000) + +/* CSI Port General 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 + +#define CSI_RX_NUM_IRQ 32U + +#define IPU7_CSI_RX_SYNC_FS_VC 0x55555555 +#define IPU7_CSI_RX_SYNC_FE_VC 0xaaaaaaaa +#define IPU7P5_CSI_RX_SYNC_FS_VC 0xffff +#define IPU7P5_CSI_RX_SYNC_FE_VC 0xffff + +#endif /* IPU7_ISYS_CSI2_REG_H */ diff --git a/drivers/staging/media/ipu7/ipu7-isys-csi2.c b/drivers/staging/media/ipu7/ipu7-isys-csi2.c new file mode 100644 index 0000000000000..9c16ae9a0e5bd --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys-csi2.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <linux/atomic.h> +#include <linux/bits.h> +#include <linux/bug.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/minmax.h> +#include <linux/mutex.h> +#include <linux/slab.h> + +#include <media/media-entity.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-subdev.h> + +#include "ipu7.h" +#include "ipu7-bus.h" +#include "ipu7-isys.h" +#include "ipu7-isys-csi2.h" +#include "ipu7-isys-csi2-regs.h" +#include "ipu7-isys-csi-phy.h" + +static const u32 csi2_supported_codes[] = { + MEDIA_BUS_FMT_Y10_1X10, + MEDIA_BUS_FMT_RGB565_1X16, + MEDIA_BUS_FMT_RGB888_1X24, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YUYV10_1X20, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SBGGR12_1X12, + MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_SGRBG12_1X12, + MEDIA_BUS_FMT_SRGGB12_1X12, + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, + 0, +}; + +s64 ipu7_isys_csi2_get_link_freq(struct ipu7_isys_csi2 *csi2) +{ + struct media_pad *src_pad; + + src_pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity); + if (IS_ERR(src_pad)) { + dev_err(&csi2->isys->adev->auxdev.dev, + "can't get source pad of %s (%ld)\n", + csi2->asd.sd.name, PTR_ERR(src_pad)); + return PTR_ERR(src_pad); + } + + return v4l2_get_link_freq(src_pad, 0, 0); +} + +static int csi2_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd); + struct ipu7_isys_csi2 *csi2 = to_ipu7_isys_csi2(asd); + struct device *dev = &csi2->isys->adev->auxdev.dev; + + dev_dbg(dev, "csi2 subscribe event(type %u id %u)\n", + sub->type, sub->id); + + switch (sub->type) { + case V4L2_EVENT_FRAME_SYNC: + return v4l2_event_subscribe(fh, sub, 10, NULL); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + default: + return -EINVAL; + } +} + +static const struct v4l2_subdev_core_ops csi2_sd_core_ops = { + .subscribe_event = csi2_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static void csi2_irq_enable(struct ipu7_isys_csi2 *csi2) +{ + struct ipu7_device *isp = csi2->isys->adev->isp; + unsigned int offset, mask; + + /* enable CSI2 legacy error irq */ + offset = IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port); + mask = IPU7_CSI_RX_ERROR_IRQ_MASK; + writel(mask, csi2->base + offset + IRQ_CTL_CLEAR); + writel(mask, csi2->base + offset + IRQ_CTL_MASK); + writel(mask, csi2->base + offset + IRQ_CTL_ENABLE); + + /* enable CSI2 legacy sync irq */ + offset = IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port); + mask = IPU7_CSI_RX_SYNC_IRQ_MASK; + writel(mask, csi2->base + offset + IRQ_CTL_CLEAR); + writel(mask, csi2->base + offset + IRQ_CTL_MASK); + writel(mask, csi2->base + offset + IRQ_CTL_ENABLE); + + mask = IPU7P5_CSI_RX_SYNC_FE_IRQ_MASK; + if (!is_ipu7(isp->hw_ver)) { + writel(mask, csi2->base + offset + IRQ1_CTL_CLEAR); + writel(mask, csi2->base + offset + IRQ1_CTL_MASK); + writel(mask, csi2->base + offset + IRQ1_CTL_ENABLE); + } +} + +static void csi2_irq_disable(struct ipu7_isys_csi2 *csi2) +{ + struct ipu7_device *isp = csi2->isys->adev->isp; + unsigned int offset, mask; + + /* disable CSI2 legacy error irq */ + offset = IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port); + mask = IPU7_CSI_RX_ERROR_IRQ_MASK; + writel(mask, csi2->base + offset + IRQ_CTL_CLEAR); + writel(0, csi2->base + offset + IRQ_CTL_MASK); + writel(0, csi2->base + offset + IRQ_CTL_ENABLE); + + /* disable CSI2 legacy sync irq */ + offset = IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port); + mask = IPU7_CSI_RX_SYNC_IRQ_MASK; + writel(mask, csi2->base + offset + IRQ_CTL_CLEAR); + writel(0, csi2->base + offset + IRQ_CTL_MASK); + writel(0, csi2->base + offset + IRQ_CTL_ENABLE); + + if (!is_ipu7(isp->hw_ver)) { + writel(mask, csi2->base + offset + IRQ1_CTL_CLEAR); + writel(0, csi2->base + offset + IRQ1_CTL_MASK); + writel(0, csi2->base + offset + IRQ1_CTL_ENABLE); + } +} + +static void ipu7_isys_csi2_disable_stream(struct ipu7_isys_csi2 *csi2) +{ + struct ipu7_isys *isys = csi2->isys; + void __iomem *isys_base = isys->pdata->base; + + ipu7_isys_csi_phy_powerdown(csi2); + + writel(0x4, isys_base + IS_IO_GPREGS_BASE + CLK_DIV_FACTOR_APB_CLK); + csi2_irq_disable(csi2); +} + +static int ipu7_isys_csi2_enable_stream(struct ipu7_isys_csi2 *csi2) +{ + struct ipu7_isys *isys = csi2->isys; + struct device *dev = &isys->adev->auxdev.dev; + void __iomem *isys_base = isys->pdata->base; + unsigned int port, nlanes, offset; + int ret; + + port = csi2->port; + nlanes = csi2->nlanes; + + offset = IS_IO_GPREGS_BASE; + writel(0x2, isys_base + offset + CLK_DIV_FACTOR_APB_CLK); + dev_dbg(dev, "port %u CLK_GATE = 0x%04x DIV_FACTOR_APB_CLK=0x%04x\n", + port, readl(isys_base + offset + CSI_PORT_CLK_GATE), + readl(isys_base + offset + CLK_DIV_FACTOR_APB_CLK)); + if (port == 0U && nlanes == 4U && !is_ipu7(isys->adev->isp->hw_ver)) { + dev_dbg(dev, "CSI port %u in aggregation mode\n", port); + writel(0x1, isys_base + offset + CSI_PORTAB_AGGREGATION); + } + + /* input is coming from CSI receiver (sensor) */ + offset = IS_IO_CSI2_ADPL_PORT_BASE(port); + writel(CSI_SENSOR_INPUT, isys_base + offset + CSI2_ADPL_INPUT_MODE); + writel(1, isys_base + offset + CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_EN); + + ret = ipu7_isys_csi_phy_powerup(csi2); + if (ret) { + dev_err(dev, "CSI-%d PHY power up failed %d\n", port, ret); + return ret; + } + + csi2_irq_enable(csi2); + + return 0; +} + +static int ipu7_isys_csi2_set_sel(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd); + struct device *dev = &asd->isys->adev->auxdev.dev; + struct v4l2_mbus_framefmt *sink_ffmt; + struct v4l2_mbus_framefmt *src_ffmt; + struct v4l2_rect *crop; + + if (sel->pad == IPU7_CSI2_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + sink_ffmt = v4l2_subdev_state_get_opposite_stream_format(state, + sel->pad, + sel->stream); + if (!sink_ffmt) + return -EINVAL; + + src_ffmt = v4l2_subdev_state_get_format(state, sel->pad, sel->stream); + if (!src_ffmt) + return -EINVAL; + + crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream); + if (!crop) + return -EINVAL; + + /* Only vertical cropping is supported */ + sel->r.left = 0; + sel->r.width = sink_ffmt->width; + /* Non-bayer formats can't be single line cropped */ + if (!ipu7_isys_is_bayer_format(sink_ffmt->code)) + sel->r.top &= ~1U; + sel->r.height = clamp(sel->r.height & ~1U, IPU_ISYS_MIN_HEIGHT, + sink_ffmt->height - sel->r.top); + *crop = sel->r; + + /* update source pad format */ + src_ffmt->width = sel->r.width; + src_ffmt->height = sel->r.height; + if (ipu7_isys_is_bayer_format(sink_ffmt->code)) + src_ffmt->code = ipu7_isys_convert_bayer_order(sink_ffmt->code, + sel->r.left, + sel->r.top); + dev_dbg(dev, "set crop for %s sel: %d,%d,%d,%d code: 0x%x\n", + sd->name, sel->r.left, sel->r.top, sel->r.width, sel->r.height, + src_ffmt->code); + + return 0; +} + +static int ipu7_isys_csi2_get_sel(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_mbus_framefmt *sink_ffmt; + struct v4l2_rect *crop; + int ret = 0; + + if (sd->entity.pads[sel->pad].flags & MEDIA_PAD_FL_SINK) + return -EINVAL; + + sink_ffmt = v4l2_subdev_state_get_opposite_stream_format(state, + sel->pad, + sel->stream); + if (!sink_ffmt) + return -EINVAL; + + crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream); + if (!crop) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = sink_ffmt->width; + sel->r.height = sink_ffmt->height; + break; + case V4L2_SEL_TGT_CROP: + sel->r = *crop; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +/* + * Maximum stream ID is 63 for now, as we use u64 bitmask to represent a set + * of streams. + */ +#define CSI2_SUBDEV_MAX_STREAM_ID 63 + +static int ipu7_isys_csi2_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd); + struct ipu7_isys_csi2 *csi2 = to_ipu7_isys_csi2(asd); + struct v4l2_subdev *r_sd; + struct media_pad *rp; + u32 sink_pad, sink_stream; + int ret, i; + + if (!csi2->stream_count) { + dev_dbg(&csi2->isys->adev->auxdev.dev, + "stream on CSI2-%u with %u lanes\n", csi2->port, + csi2->nlanes); + ret = ipu7_isys_csi2_enable_stream(csi2); + if (ret) + return ret; + } + + for (i = 0; i <= CSI2_SUBDEV_MAX_STREAM_ID; i++) { + if (streams_mask & BIT_ULL(i)) + break; + } + + ret = v4l2_subdev_routing_find_opposite_end(&state->routing, pad, i, + &sink_pad, &sink_stream); + if (ret) + return ret; + + rp = media_pad_remote_pad_first(&sd->entity.pads[IPU7_CSI2_PAD_SINK]); + r_sd = media_entity_to_v4l2_subdev(rp->entity); + + ret = v4l2_subdev_enable_streams(r_sd, rp->index, + BIT_ULL(sink_stream)); + if (!ret) { + csi2->stream_count++; + return 0; + } + + if (!csi2->stream_count) + ipu7_isys_csi2_disable_stream(csi2); + + return ret; +} + +static int ipu7_isys_csi2_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd); + struct ipu7_isys_csi2 *csi2 = to_ipu7_isys_csi2(asd); + struct v4l2_subdev *r_sd; + struct media_pad *rp; + u32 sink_pad, sink_stream; + int ret, i; + + for (i = 0; i <= CSI2_SUBDEV_MAX_STREAM_ID; i++) { + if (streams_mask & BIT_ULL(i)) + break; + } + + ret = v4l2_subdev_routing_find_opposite_end(&state->routing, pad, i, + &sink_pad, &sink_stream); + if (ret) + return ret; + + rp = media_pad_remote_pad_first(&sd->entity.pads[IPU7_CSI2_PAD_SINK]); + r_sd = media_entity_to_v4l2_subdev(rp->entity); + + v4l2_subdev_disable_streams(r_sd, rp->index, BIT_ULL(sink_stream)); + + if (--csi2->stream_count) + return 0; + + dev_dbg(&csi2->isys->adev->auxdev.dev, + "stream off CSI2-%u with %u lanes\n", csi2->port, csi2->nlanes); + + ipu7_isys_csi2_disable_stream(csi2); + + return 0; +} + +static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ipu7_isys_subdev_set_fmt, + .get_selection = ipu7_isys_csi2_get_sel, + .set_selection = ipu7_isys_csi2_set_sel, + .enum_mbus_code = ipu7_isys_subdev_enum_mbus_code, + .enable_streams = ipu7_isys_csi2_enable_streams, + .disable_streams = ipu7_isys_csi2_disable_streams, + .set_routing = ipu7_isys_subdev_set_routing, +}; + +static const struct v4l2_subdev_ops csi2_sd_ops = { + .core = &csi2_sd_core_ops, + .pad = &csi2_sd_pad_ops, +}; + +static const struct media_entity_operations csi2_entity_ops = { + .link_validate = v4l2_subdev_link_validate, + .has_pad_interdep = v4l2_subdev_has_pad_interdep, +}; + +void ipu7_isys_csi2_cleanup(struct ipu7_isys_csi2 *csi2) +{ + if (!csi2->isys) + return; + + v4l2_device_unregister_subdev(&csi2->asd.sd); + v4l2_subdev_cleanup(&csi2->asd.sd); + ipu7_isys_subdev_cleanup(&csi2->asd); + csi2->isys = NULL; +} + +int ipu7_isys_csi2_init(struct ipu7_isys_csi2 *csi2, + struct ipu7_isys *isys, + void __iomem *base, unsigned int index) +{ + struct device *dev = &isys->adev->auxdev.dev; + int ret; + + csi2->isys = isys; + csi2->base = base; + csi2->port = index; + + if (!is_ipu7(isys->adev->isp->hw_ver)) + csi2->legacy_irq_mask = 0x7U << (index * 3U); + else + csi2->legacy_irq_mask = 0x3U << (index * 2U); + + dev_dbg(dev, "csi-%d legacy irq mask = 0x%x\n", index, + csi2->legacy_irq_mask); + + csi2->asd.sd.entity.ops = &csi2_entity_ops; + csi2->asd.isys = isys; + + ret = ipu7_isys_subdev_init(&csi2->asd, &csi2_sd_ops, 0, + IPU7_NR_OF_CSI2_SINK_PADS, + IPU7_NR_OF_CSI2_SRC_PADS); + if (ret) + return ret; + + csi2->asd.source = (int)index; + csi2->asd.supported_codes = csi2_supported_codes; + snprintf(csi2->asd.sd.name, sizeof(csi2->asd.sd.name), + IPU_ISYS_ENTITY_PREFIX " CSI2 %u", index); + v4l2_set_subdevdata(&csi2->asd.sd, &csi2->asd); + + ret = v4l2_subdev_init_finalize(&csi2->asd.sd); + if (ret) { + dev_err(dev, "failed to init v4l2 subdev (%d)\n", ret); + goto isys_subdev_cleanup; + } + + ret = v4l2_device_register_subdev(&isys->v4l2_dev, &csi2->asd.sd); + if (ret) { + dev_err(dev, "failed to register v4l2 subdev (%d)\n", ret); + goto v4l2_subdev_cleanup; + } + + return 0; + +v4l2_subdev_cleanup: + v4l2_subdev_cleanup(&csi2->asd.sd); +isys_subdev_cleanup: + ipu7_isys_subdev_cleanup(&csi2->asd); + + return ret; +} + +void ipu7_isys_csi2_sof_event_by_stream(struct ipu7_isys_stream *stream) +{ + struct ipu7_isys_csi2 *csi2 = ipu7_isys_subdev_to_csi2(stream->asd); + struct device *dev = &stream->isys->adev->auxdev.dev; + struct video_device *vdev = csi2->asd.sd.devnode; + struct v4l2_event ev = { + .type = V4L2_EVENT_FRAME_SYNC, + }; + + ev.id = stream->vc; + ev.u.frame_sync.frame_sequence = atomic_fetch_inc(&stream->sequence); + v4l2_event_queue(vdev, &ev); + + dev_dbg(dev, "sof_event::csi2-%i sequence: %i, vc: %d\n", + csi2->port, ev.u.frame_sync.frame_sequence, stream->vc); +} + +void ipu7_isys_csi2_eof_event_by_stream(struct ipu7_isys_stream *stream) +{ + struct ipu7_isys_csi2 *csi2 = ipu7_isys_subdev_to_csi2(stream->asd); + struct device *dev = &stream->isys->adev->auxdev.dev; + u32 frame_sequence = atomic_read(&stream->sequence); + + dev_dbg(dev, "eof_event::csi2-%i sequence: %i\n", + csi2->port, frame_sequence); +} + +int ipu7_isys_csi2_get_remote_desc(u32 source_stream, + struct ipu7_isys_csi2 *csi2, + struct media_entity *source_entity, + struct v4l2_mbus_frame_desc_entry *entry, + int *nr_queues) +{ + struct v4l2_mbus_frame_desc_entry *desc_entry = NULL; + struct device *dev = &csi2->isys->adev->auxdev.dev; + struct v4l2_mbus_frame_desc desc; + struct v4l2_subdev *source; + struct media_pad *pad; + unsigned int i; + int ret; + + source = media_entity_to_v4l2_subdev(source_entity); + if (!source) + return -EPIPE; + + pad = media_pad_remote_pad_first(&csi2->asd.pad[IPU7_CSI2_PAD_SINK]); + if (!pad) + return -EPIPE; + + ret = v4l2_subdev_call(source, pad, get_frame_desc, pad->index, &desc); + if (ret) + return ret; + + if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { + dev_err(dev, "Unsupported frame descriptor type\n"); + return -EINVAL; + } + + for (i = 0; i < desc.num_entries; i++) { + if (source_stream == desc.entry[i].stream) { + desc_entry = &desc.entry[i]; + break; + } + } + + if (!desc_entry) { + dev_err(dev, "Failed to find stream %u from remote subdev\n", + source_stream); + return -EINVAL; + } + + if (desc_entry->bus.csi2.vc >= IPU7_NR_OF_CSI2_VC) { + dev_err(dev, "invalid vc %d\n", desc_entry->bus.csi2.vc); + return -EINVAL; + } + + *entry = *desc_entry; + + for (i = 0; i < desc.num_entries; i++) { + if (desc_entry->bus.csi2.vc == desc.entry[i].bus.csi2.vc) + (*nr_queues)++; + } + + return 0; +} diff --git a/drivers/staging/media/ipu7/ipu7-isys-csi2.h b/drivers/staging/media/ipu7/ipu7-isys-csi2.h new file mode 100644 index 0000000000000..6c23b80f92a2a --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys-csi2.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#ifndef IPU7_ISYS_CSI2_H +#define IPU7_ISYS_CSI2_H + +#include <linux/container_of.h> +#include <linux/types.h> + +#include "ipu7-isys-subdev.h" +#include "ipu7-isys-video.h" + +struct ipu7_isys; +struct ipu7_isys_csi2_pdata; +struct ipu7_isys_stream; + +#define IPU7_NR_OF_CSI2_VC 16U +#define INVALID_VC_ID -1 +#define IPU7_NR_OF_CSI2_SINK_PADS 1U +#define IPU7_CSI2_PAD_SINK 0U +#define IPU7_NR_OF_CSI2_SRC_PADS 8U +#define IPU7_CSI2_PAD_SRC 1U +#define IPU7_NR_OF_CSI2_PADS (IPU7_NR_OF_CSI2_SINK_PADS + \ + IPU7_NR_OF_CSI2_SRC_PADS) + +/* + * struct ipu7_isys_csi2 + * + * @nlanes: number of lanes in the receiver + */ +struct ipu7_isys_csi2 { + struct ipu7_isys_subdev asd; + struct ipu7_isys_csi2_pdata *pdata; + struct ipu7_isys *isys; + struct ipu7_isys_video av[IPU7_NR_OF_CSI2_SRC_PADS]; + + void __iomem *base; + u32 receiver_errors; + u32 legacy_irq_mask; + unsigned int nlanes; + unsigned int port; + unsigned int phy_mode; + unsigned int stream_count; +}; + +#define ipu7_isys_subdev_to_csi2(__sd) \ + container_of(__sd, struct ipu7_isys_csi2, asd) + +#define to_ipu7_isys_csi2(__asd) container_of(__asd, struct ipu7_isys_csi2, asd) + +s64 ipu7_isys_csi2_get_link_freq(struct ipu7_isys_csi2 *csi2); +int ipu7_isys_csi2_init(struct ipu7_isys_csi2 *csi2, struct ipu7_isys *isys, + void __iomem *base, unsigned int index); +void ipu7_isys_csi2_cleanup(struct ipu7_isys_csi2 *csi2); +void ipu7_isys_csi2_sof_event_by_stream(struct ipu7_isys_stream *stream); +void ipu7_isys_csi2_eof_event_by_stream(struct ipu7_isys_stream *stream); +int ipu7_isys_csi2_get_remote_desc(u32 source_stream, + struct ipu7_isys_csi2 *csi2, + struct media_entity *source_entity, + struct v4l2_mbus_frame_desc_entry *entry, + int *nr_queues); +#endif /* IPU7_ISYS_CSI2_H */ diff --git a/drivers/staging/media/ipu7/ipu7-isys-queue.c b/drivers/staging/media/ipu7/ipu7-isys-queue.c new file mode 100644 index 0000000000000..7046c29141f80 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys-queue.c @@ -0,0 +1,829 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <linux/atomic.h> +#include <linux/bug.h> +#include <linux/device.h> +#include <linux/list.h> +#include <linux/lockdep.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/types.h> + +#include <media/media-entity.h> +#include <media/v4l2-subdev.h> +#include <media/videobuf2-dma-sg.h> +#include <media/videobuf2-v4l2.h> + +#include "abi/ipu7_fw_isys_abi.h" + +#include "ipu7-bus.h" +#include "ipu7-dma.h" +#include "ipu7-fw-isys.h" +#include "ipu7-isys.h" +#include "ipu7-isys-csi2-regs.h" +#include "ipu7-isys-video.h" +#include "ipu7-platform-regs.h" + +#define IPU_MAX_FRAME_COUNTER (U8_MAX + 1) + +static int ipu7_isys_buf_init(struct vb2_buffer *vb) +{ + struct ipu7_isys *isys = vb2_get_drv_priv(vb->vb2_queue); + struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0); + struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb); + struct ipu7_isys_video_buffer *ivb = + vb2_buffer_to_ipu7_isys_video_buffer(vvb); + int ret; + + ret = ipu7_dma_map_sgtable(isys->adev, sg, DMA_TO_DEVICE, 0); + if (ret) + return ret; + + ivb->dma_addr = sg_dma_address(sg->sgl); + + return 0; +} + +static void ipu7_isys_buf_cleanup(struct vb2_buffer *vb) +{ + struct ipu7_isys *isys = vb2_get_drv_priv(vb->vb2_queue); + struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0); + struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb); + struct ipu7_isys_video_buffer *ivb = + vb2_buffer_to_ipu7_isys_video_buffer(vvb); + + ivb->dma_addr = 0; + ipu7_dma_unmap_sgtable(isys->adev, sg, DMA_TO_DEVICE, 0); +} + +static int ipu7_isys_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(q); + struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq); + struct device *dev = &av->isys->adev->auxdev.dev; + u32 size = av->pix_fmt.sizeimage; + + /* num_planes == 0: we're being called through VIDIOC_REQBUFS */ + if (!*num_planes) { + sizes[0] = size; + } else if (sizes[0] < size) { + dev_dbg(dev, "%s: queue setup: size %u < %u\n", + av->vdev.name, sizes[0], size); + return -EINVAL; + } + + *num_planes = 1; + + return 0; +} + +static int ipu7_isys_buf_prepare(struct vb2_buffer *vb) +{ + struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue); + struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq); + struct device *dev = &av->isys->adev->auxdev.dev; + u32 bytesperline = av->pix_fmt.bytesperline; + u32 height = av->pix_fmt.height; + + dev_dbg(dev, "buffer: %s: configured size %u, buffer size %lu\n", + av->vdev.name, av->pix_fmt.sizeimage, vb2_plane_size(vb, 0)); + + if (av->pix_fmt.sizeimage > vb2_plane_size(vb, 0)) + return -EINVAL; + + dev_dbg(dev, "buffer: %s: bytesperline %u, height %u\n", + av->vdev.name, bytesperline, height); + vb2_set_plane_payload(vb, 0, bytesperline * height); + + return 0; +} + +/* + * Queue a buffer list back to incoming or active queues. The buffers + * are removed from the buffer list. + */ +void ipu7_isys_buffer_list_queue(struct ipu7_isys_buffer_list *bl, + unsigned long op_flags, + enum vb2_buffer_state state) +{ + struct ipu7_isys_buffer *ib, *ib_safe; + unsigned long flags; + bool first = true; + + if (!bl) + return; + + WARN_ON_ONCE(!bl->nbufs); + WARN_ON_ONCE(op_flags & IPU_ISYS_BUFFER_LIST_FL_ACTIVE && + op_flags & IPU_ISYS_BUFFER_LIST_FL_INCOMING); + + list_for_each_entry_safe(ib, ib_safe, &bl->head, head) { + struct ipu7_isys_video *av; + + struct vb2_buffer *vb = ipu7_isys_buffer_to_vb2_buffer(ib); + struct ipu7_isys_queue *aq = + vb2_queue_to_isys_queue(vb->vb2_queue); + + av = ipu7_isys_queue_to_video(aq); + spin_lock_irqsave(&aq->lock, flags); + list_del(&ib->head); + if (op_flags & IPU_ISYS_BUFFER_LIST_FL_ACTIVE) + list_add(&ib->head, &aq->active); + else if (op_flags & IPU_ISYS_BUFFER_LIST_FL_INCOMING) + list_add_tail(&ib->head, &aq->incoming); + spin_unlock_irqrestore(&aq->lock, flags); + + if (op_flags & IPU_ISYS_BUFFER_LIST_FL_SET_STATE) + vb2_buffer_done(vb, state); + + if (first) { + dev_dbg(&av->isys->adev->auxdev.dev, + "queue buf list %p flags %lx, s %d, %d bufs\n", + bl, op_flags, state, bl->nbufs); + first = false; + } + + bl->nbufs--; + } + + WARN_ON(bl->nbufs); +} + +/* + * flush_firmware_streamon_fail() - Flush in cases where requests may + * have been queued to firmware and the *firmware streamon fails for a + * reason or another. + */ +static void flush_firmware_streamon_fail(struct ipu7_isys_stream *stream) +{ + struct ipu7_isys_queue *aq; + unsigned long flags; + + lockdep_assert_held(&stream->mutex); + + list_for_each_entry(aq, &stream->queues, node) { + struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq); + struct device *dev = &av->isys->adev->auxdev.dev; + struct ipu7_isys_buffer *ib, *ib_safe; + + spin_lock_irqsave(&aq->lock, flags); + list_for_each_entry_safe(ib, ib_safe, &aq->active, head) { + struct vb2_buffer *vb = + ipu7_isys_buffer_to_vb2_buffer(ib); + + list_del(&ib->head); + if (av->streaming) { + dev_dbg(dev, + "%s: queue buffer %u back to incoming\n", + av->vdev.name, vb->index); + /* Queue already streaming, return to driver. */ + list_add(&ib->head, &aq->incoming); + continue; + } + /* Queue not yet streaming, return to user. */ + dev_dbg(dev, "%s: return %u back to videobuf2\n", + av->vdev.name, vb->index); + vb2_buffer_done(ipu7_isys_buffer_to_vb2_buffer(ib), + VB2_BUF_STATE_QUEUED); + } + spin_unlock_irqrestore(&aq->lock, flags); + } +} + +/* + * Attempt obtaining a buffer list from the incoming queues, a list of buffers + * that contains one entry from each video buffer queue. If a buffer can't be + * obtained from every queue, the buffers are returned back to the queue. + */ +static int buffer_list_get(struct ipu7_isys_stream *stream, + struct ipu7_isys_buffer_list *bl) +{ + unsigned long buf_flag = IPU_ISYS_BUFFER_LIST_FL_INCOMING; + struct device *dev = &stream->isys->adev->auxdev.dev; + struct ipu7_isys_queue *aq; + unsigned long flags; + + bl->nbufs = 0; + INIT_LIST_HEAD(&bl->head); + + list_for_each_entry(aq, &stream->queues, node) { + struct ipu7_isys_buffer *ib; + + spin_lock_irqsave(&aq->lock, flags); + if (list_empty(&aq->incoming)) { + spin_unlock_irqrestore(&aq->lock, flags); + if (!list_empty(&bl->head)) + ipu7_isys_buffer_list_queue(bl, buf_flag, 0); + return -ENODATA; + } + + ib = list_last_entry(&aq->incoming, + struct ipu7_isys_buffer, head); + + dev_dbg(dev, "buffer: %s: buffer %u\n", + ipu7_isys_queue_to_video(aq)->vdev.name, + ipu7_isys_buffer_to_vb2_buffer(ib)->index); + list_del(&ib->head); + list_add(&ib->head, &bl->head); + spin_unlock_irqrestore(&aq->lock, flags); + + bl->nbufs++; + } + + dev_dbg(dev, "get buffer list %p, %u buffers\n", bl, bl->nbufs); + + return 0; +} + +static void ipu7_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb, + struct ipu7_insys_buffset *set) +{ + struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue); + struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb); + struct ipu7_isys_video_buffer *ivb = + vb2_buffer_to_ipu7_isys_video_buffer(vvb); + + set->output_pins[aq->fw_output].addr = ivb->dma_addr; + set->output_pins[aq->fw_output].user_token = (uintptr_t)set; +} + +/* + * Convert a buffer list to a isys fw ABI framebuffer set. The + * buffer list is not modified. + */ +#define IPU_ISYS_FRAME_NUM_THRESHOLD (30) +void ipu7_isys_buffer_to_fw_frame_buff(struct ipu7_insys_buffset *set, + struct ipu7_isys_stream *stream, + struct ipu7_isys_buffer_list *bl) +{ + struct ipu7_isys_buffer *ib; + u32 buf_id; + + WARN_ON(!bl->nbufs); + + set->skip_frame = 0; + set->capture_msg_map = IPU_INSYS_FRAME_ENABLE_MSG_SEND_RESP | + IPU_INSYS_FRAME_ENABLE_MSG_SEND_IRQ; + + buf_id = atomic_fetch_inc(&stream->buf_id); + set->frame_id = buf_id % IPU_MAX_FRAME_COUNTER; + + list_for_each_entry(ib, &bl->head, head) { + struct vb2_buffer *vb = ipu7_isys_buffer_to_vb2_buffer(ib); + + ipu7_isys_buf_to_fw_frame_buf_pin(vb, set); + } +} + +/* Start streaming for real. The buffer list must be available. */ +static int ipu7_isys_stream_start(struct ipu7_isys_video *av, + struct ipu7_isys_buffer_list *bl, bool error) +{ + struct ipu7_isys_stream *stream = av->stream; + struct device *dev = &stream->isys->adev->auxdev.dev; + struct ipu7_isys_buffer_list __bl; + int ret; + + mutex_lock(&stream->isys->stream_mutex); + + ret = ipu7_isys_video_set_streaming(av, 1, bl); + mutex_unlock(&stream->isys->stream_mutex); + if (ret) + goto out_requeue; + + stream->streaming = 1; + + bl = &__bl; + + do { + struct ipu7_insys_buffset *buf = NULL; + struct isys_fw_msgs *msg; + enum ipu7_insys_send_type send_type = + IPU_INSYS_SEND_TYPE_STREAM_CAPTURE; + + ret = buffer_list_get(stream, bl); + if (ret < 0) + break; + + msg = ipu7_get_fw_msg_buf(stream); + if (!msg) + return -ENOMEM; + + buf = &msg->fw_msg.frame; + + ipu7_isys_buffer_to_fw_frame_buff(buf, stream, bl); + + ipu7_fw_isys_dump_frame_buff_set(dev, buf, + stream->nr_output_pins); + + ipu7_isys_buffer_list_queue(bl, IPU_ISYS_BUFFER_LIST_FL_ACTIVE, + 0); + + ret = ipu7_fw_isys_complex_cmd(stream->isys, + stream->stream_handle, buf, + msg->dma_addr, sizeof(*buf), + send_type); + } while (!WARN_ON(ret)); + + return 0; + +out_requeue: + if (bl && bl->nbufs) + ipu7_isys_buffer_list_queue(bl, + IPU_ISYS_BUFFER_LIST_FL_INCOMING | + (error ? + IPU_ISYS_BUFFER_LIST_FL_SET_STATE : + 0), error ? VB2_BUF_STATE_ERROR : + VB2_BUF_STATE_QUEUED); + flush_firmware_streamon_fail(stream); + + return ret; +} + +static void buf_queue(struct vb2_buffer *vb) +{ + struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue); + struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq); + struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb); + struct ipu7_isys_video_buffer *ivb = + vb2_buffer_to_ipu7_isys_video_buffer(vvb); + struct media_pipeline *media_pipe = + media_entity_pipeline(&av->vdev.entity); + struct device *dev = &av->isys->adev->auxdev.dev; + struct ipu7_isys_stream *stream = av->stream; + struct ipu7_isys_buffer *ib = &ivb->ib; + struct ipu7_insys_buffset *buf = NULL; + struct ipu7_isys_buffer_list bl; + struct isys_fw_msgs *msg; + unsigned long flags; + dma_addr_t dma; + int ret; + + dev_dbg(dev, "queue buffer %u for %s\n", vb->index, av->vdev.name); + + dma = ivb->dma_addr; + dev_dbg(dev, "iova: iova %pad\n", &dma); + + spin_lock_irqsave(&aq->lock, flags); + list_add(&ib->head, &aq->incoming); + spin_unlock_irqrestore(&aq->lock, flags); + + if (!media_pipe || !vb->vb2_queue->start_streaming_called) { + dev_dbg(dev, "media pipeline is not ready for %s\n", + av->vdev.name); + return; + } + + mutex_lock(&stream->mutex); + + if (stream->nr_streaming != stream->nr_queues) { + dev_dbg(dev, "not streaming yet, adding to incoming\n"); + goto out; + } + + /* + * We just put one buffer to the incoming list of this queue + * (above). Let's see whether all queues in the pipeline would + * have a buffer. + */ + ret = buffer_list_get(stream, &bl); + if (ret < 0) { + dev_dbg(dev, "No buffers available\n"); + goto out; + } + + msg = ipu7_get_fw_msg_buf(stream); + if (!msg) { + ret = -ENOMEM; + goto out; + } + + buf = &msg->fw_msg.frame; + + ipu7_isys_buffer_to_fw_frame_buff(buf, stream, &bl); + + ipu7_fw_isys_dump_frame_buff_set(dev, buf, stream->nr_output_pins); + + if (!stream->streaming) { + ret = ipu7_isys_stream_start(av, &bl, true); + if (ret) + dev_err(dev, "stream start failed.\n"); + goto out; + } + + /* + * We must queue the buffers in the buffer list to the + * appropriate video buffer queues BEFORE passing them to the + * firmware since we could get a buffer event back before we + * have queued them ourselves to the active queue. + */ + ipu7_isys_buffer_list_queue(&bl, IPU_ISYS_BUFFER_LIST_FL_ACTIVE, 0); + + ret = ipu7_fw_isys_complex_cmd(stream->isys, stream->stream_handle, + buf, msg->dma_addr, sizeof(*buf), + IPU_INSYS_SEND_TYPE_STREAM_CAPTURE); + if (ret < 0) + dev_err(dev, "send stream capture failed\n"); + +out: + mutex_unlock(&stream->mutex); +} + +static int ipu7_isys_link_fmt_validate(struct ipu7_isys_queue *aq) +{ + struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq); + struct device *dev = &av->isys->adev->auxdev.dev; + struct media_pad *remote_pad = + media_pad_remote_pad_first(av->vdev.entity.pads); + struct v4l2_mbus_framefmt format; + struct v4l2_subdev *sd; + u32 r_stream, code; + int ret; + + if (!remote_pad) + return -ENOTCONN; + + sd = media_entity_to_v4l2_subdev(remote_pad->entity); + r_stream = ipu7_isys_get_src_stream_by_src_pad(sd, remote_pad->index); + + ret = ipu7_isys_get_stream_pad_fmt(sd, remote_pad->index, r_stream, + &format); + if (ret) { + dev_dbg(dev, "failed to get %s: pad %d, stream:%d format\n", + sd->entity.name, remote_pad->index, r_stream); + return ret; + } + + if (format.width != av->pix_fmt.width || + format.height != av->pix_fmt.height) { + dev_dbg(dev, "wrong width or height %ux%u (%ux%u expected)\n", + av->pix_fmt.width, av->pix_fmt.height, format.width, + format.height); + return -EINVAL; + } + + code = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat)->code; + if (format.code != code) { + dev_dbg(dev, "wrong mbus code 0x%8.8x (0x%8.8x expected)\n", + code, format.code); + return -EINVAL; + } + + return 0; +} + +static void return_buffers(struct ipu7_isys_queue *aq, + enum vb2_buffer_state state) +{ + struct ipu7_isys_buffer *ib; + struct vb2_buffer *vb; + unsigned long flags; + + spin_lock_irqsave(&aq->lock, flags); + /* + * Something went wrong (FW crash / HW hang / not all buffers + * returned from isys) if there are still buffers queued in active + * queue. We have to clean up places a bit. + */ + while (!list_empty(&aq->active)) { + ib = list_last_entry(&aq->active, struct ipu7_isys_buffer, + head); + vb = ipu7_isys_buffer_to_vb2_buffer(ib); + + list_del(&ib->head); + spin_unlock_irqrestore(&aq->lock, flags); + + vb2_buffer_done(vb, state); + + spin_lock_irqsave(&aq->lock, flags); + } + + while (!list_empty(&aq->incoming)) { + ib = list_last_entry(&aq->incoming, struct ipu7_isys_buffer, + head); + vb = ipu7_isys_buffer_to_vb2_buffer(ib); + list_del(&ib->head); + spin_unlock_irqrestore(&aq->lock, flags); + + vb2_buffer_done(vb, state); + + spin_lock_irqsave(&aq->lock, flags); + } + + spin_unlock_irqrestore(&aq->lock, flags); +} + +static void ipu7_isys_stream_cleanup(struct ipu7_isys_video *av) +{ + video_device_pipeline_stop(&av->vdev); + ipu7_isys_put_stream(av->stream); + av->stream = NULL; +} + +static int start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(q); + struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq); + struct device *dev = &av->isys->adev->auxdev.dev; + const struct ipu7_isys_pixelformat *pfmt = + ipu7_isys_get_isys_format(av->pix_fmt.pixelformat); + struct ipu7_isys_buffer_list __bl, *bl = NULL; + struct ipu7_isys_stream *stream; + struct media_entity *source_entity = NULL; + int nr_queues, ret; + + dev_dbg(dev, "stream: %s: width %u, height %u, css pixelformat %u\n", + av->vdev.name, av->pix_fmt.width, av->pix_fmt.height, + pfmt->css_pixelformat); + + ret = ipu7_isys_setup_video(av, &source_entity, &nr_queues); + if (ret < 0) { + dev_dbg(dev, "failed to setup video\n"); + goto out_return_buffers; + } + + ret = ipu7_isys_link_fmt_validate(aq); + if (ret) { + dev_dbg(dev, + "%s: link format validation failed (%d)\n", + av->vdev.name, ret); + goto out_pipeline_stop; + } + + stream = av->stream; + mutex_lock(&stream->mutex); + if (!stream->nr_streaming) { + ret = ipu7_isys_video_prepare_stream(av, source_entity, + nr_queues); + if (ret) { + mutex_unlock(&stream->mutex); + goto out_pipeline_stop; + } + } + + stream->nr_streaming++; + dev_dbg(dev, "queue %u of %u\n", stream->nr_streaming, + stream->nr_queues); + + list_add(&aq->node, &stream->queues); + + if (stream->nr_streaming != stream->nr_queues) + goto out; + + bl = &__bl; + ret = buffer_list_get(stream, bl); + if (ret < 0) { + dev_warn(dev, "no buffer available, DRIVER BUG?\n"); + goto out; + } + + ret = ipu7_isys_fw_open(av->isys); + if (ret) + goto out_stream_start; + + ipu7_isys_setup_hw(av->isys); + + ret = ipu7_isys_stream_start(av, bl, false); + if (ret) + goto out_isys_fw_close; + +out: + mutex_unlock(&stream->mutex); + + return 0; + +out_isys_fw_close: + ipu7_isys_fw_close(av->isys); + +out_stream_start: + list_del(&aq->node); + stream->nr_streaming--; + mutex_unlock(&stream->mutex); + +out_pipeline_stop: + ipu7_isys_stream_cleanup(av); + +out_return_buffers: + return_buffers(aq, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static void stop_streaming(struct vb2_queue *q) +{ + struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(q); + struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq); + struct ipu7_isys_stream *stream = av->stream; + + mutex_lock(&stream->mutex); + mutex_lock(&av->isys->stream_mutex); + if (stream->nr_streaming == stream->nr_queues && stream->streaming) + ipu7_isys_video_set_streaming(av, 0, NULL); + mutex_unlock(&av->isys->stream_mutex); + + stream->nr_streaming--; + list_del(&aq->node); + stream->streaming = 0; + + mutex_unlock(&stream->mutex); + + ipu7_isys_stream_cleanup(av); + + return_buffers(aq, VB2_BUF_STATE_ERROR); + + ipu7_isys_fw_close(av->isys); +} + +static unsigned int +get_sof_sequence_by_timestamp(struct ipu7_isys_stream *stream, u64 time) +{ + struct ipu7_isys *isys = stream->isys; + struct device *dev = &isys->adev->auxdev.dev; + unsigned int i; + + /* + * The timestamp is invalid as no TSC in some FPGA platform, + * so get the sequence from pipeline directly in this case. + */ + if (time == 0) + return atomic_read(&stream->sequence) - 1; + + for (i = 0; i < IPU_ISYS_MAX_PARALLEL_SOF; i++) + if (time == stream->seq[i].timestamp) { + dev_dbg(dev, "SOF: using seq nr %u for ts %llu\n", + stream->seq[i].sequence, time); + return stream->seq[i].sequence; + } + + dev_dbg(dev, "SOF: looking for %llu\n", time); + for (i = 0; i < IPU_ISYS_MAX_PARALLEL_SOF; i++) + dev_dbg(dev, "SOF: sequence %u, timestamp value %llu\n", + stream->seq[i].sequence, stream->seq[i].timestamp); + dev_dbg(dev, "SOF sequence number not found\n"); + + return atomic_read(&stream->sequence) - 1; +} + +static u64 get_sof_ns_delta(struct ipu7_isys_video *av, u64 time) +{ + struct ipu7_bus_device *adev = av->isys->adev; + struct ipu7_device *isp = adev->isp; + u64 delta, tsc_now; + + ipu_buttress_tsc_read(isp, &tsc_now); + if (!tsc_now) + return 0; + + delta = tsc_now - time; + + return ipu_buttress_tsc_ticks_to_ns(delta, isp); +} + +static void ipu7_isys_buf_calc_sequence_time(struct ipu7_isys_buffer *ib, + u64 time) +{ + struct vb2_buffer *vb = ipu7_isys_buffer_to_vb2_buffer(ib); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct ipu7_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue); + struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq); + struct device *dev = &av->isys->adev->auxdev.dev; + struct ipu7_isys_stream *stream = av->stream; + u64 ns; + u32 sequence; + + ns = ktime_get_ns() - get_sof_ns_delta(av, time); + sequence = get_sof_sequence_by_timestamp(stream, time); + + vbuf->vb2_buf.timestamp = ns; + vbuf->sequence = sequence; + + dev_dbg(dev, "buf: %s: buffer done, CPU-timestamp:%lld, sequence:%d\n", + av->vdev.name, ktime_get_ns(), sequence); + dev_dbg(dev, "index:%d, vbuf timestamp:%lld\n", vb->index, + vbuf->vb2_buf.timestamp); +} + +static void ipu7_isys_queue_buf_done(struct ipu7_isys_buffer *ib) +{ + struct vb2_buffer *vb = ipu7_isys_buffer_to_vb2_buffer(ib); + + if (atomic_read(&ib->str2mmio_flag)) { + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + /* + * Operation on buffer is ended with error and will be reported + * to the userspace when it is de-queued + */ + atomic_set(&ib->str2mmio_flag, 0); + } else { + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + } +} + +void ipu7_isys_queue_buf_ready(struct ipu7_isys_stream *stream, + struct ipu7_insys_resp *info) +{ + struct ipu7_isys_queue *aq = stream->output_pins[info->pin_id].aq; + u64 time = ((u64)info->timestamp[1] << 32 | info->timestamp[0]); + struct ipu7_isys *isys = stream->isys; + struct device *dev = &isys->adev->auxdev.dev; + struct ipu7_isys_buffer *ib; + struct vb2_buffer *vb; + unsigned long flags; + bool first = true; + struct vb2_v4l2_buffer *buf; + + dev_dbg(dev, "buffer: %s: received buffer %8.8x %d\n", + ipu7_isys_queue_to_video(aq)->vdev.name, info->pin.addr, + info->frame_id); + + spin_lock_irqsave(&aq->lock, flags); + if (list_empty(&aq->active)) { + spin_unlock_irqrestore(&aq->lock, flags); + dev_err(dev, "active queue empty\n"); + return; + } + + list_for_each_entry_reverse(ib, &aq->active, head) { + struct ipu7_isys_video_buffer *ivb; + struct vb2_v4l2_buffer *vvb; + dma_addr_t addr; + + vb = ipu7_isys_buffer_to_vb2_buffer(ib); + vvb = to_vb2_v4l2_buffer(vb); + ivb = vb2_buffer_to_ipu7_isys_video_buffer(vvb); + addr = ivb->dma_addr; + + if (info->pin.addr != addr) { + if (first) + dev_err(dev, "Unexpected buffer address %pad\n", + &addr); + + first = false; + continue; + } + + dev_dbg(dev, "buffer: found buffer %pad\n", &addr); + + buf = to_vb2_v4l2_buffer(vb); + buf->field = V4L2_FIELD_NONE; + + list_del(&ib->head); + spin_unlock_irqrestore(&aq->lock, flags); + + ipu7_isys_buf_calc_sequence_time(ib, time); + + ipu7_isys_queue_buf_done(ib); + + return; + } + + dev_err(dev, "Failed to find a matching video buffer\n"); + + spin_unlock_irqrestore(&aq->lock, flags); +} + +static const struct vb2_ops ipu7_isys_queue_ops = { + .queue_setup = ipu7_isys_queue_setup, + .buf_init = ipu7_isys_buf_init, + .buf_prepare = ipu7_isys_buf_prepare, + .buf_cleanup = ipu7_isys_buf_cleanup, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .buf_queue = buf_queue, +}; + +int ipu7_isys_queue_init(struct ipu7_isys_queue *aq) +{ + struct ipu7_isys *isys = ipu7_isys_queue_to_video(aq)->isys; + struct ipu7_isys_video *av = ipu7_isys_queue_to_video(aq); + struct ipu7_bus_device *adev = isys->adev; + int ret; + + if (!aq->vbq.io_modes) + aq->vbq.io_modes = VB2_MMAP | VB2_DMABUF; + + aq->vbq.drv_priv = isys; + aq->vbq.ops = &ipu7_isys_queue_ops; + aq->vbq.lock = &av->mutex; + aq->vbq.mem_ops = &vb2_dma_sg_memops; + aq->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + aq->vbq.min_queued_buffers = 1; + aq->vbq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + + ret = vb2_queue_init(&aq->vbq); + if (ret) + return ret; + + aq->dev = &adev->auxdev.dev; + aq->vbq.dev = &adev->isp->pdev->dev; + spin_lock_init(&aq->lock); + INIT_LIST_HEAD(&aq->active); + INIT_LIST_HEAD(&aq->incoming); + + return 0; +} diff --git a/drivers/staging/media/ipu7/ipu7-isys-queue.h b/drivers/staging/media/ipu7/ipu7-isys-queue.h new file mode 100644 index 0000000000000..0cb08a38f756b --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys-queue.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#ifndef IPU7_ISYS_QUEUE_H +#define IPU7_ISYS_QUEUE_H + +#include <linux/atomic.h> +#include <linux/container_of.h> +#include <linux/list.h> +#include <linux/spinlock_types.h> + +#include <media/videobuf2-v4l2.h> + +struct device; +struct ipu7_isys_stream; +struct ipu7_insys_resp; +struct ipu7_insys_buffset; + +struct ipu7_isys_queue { + struct vb2_queue vbq; + struct list_head node; + struct device *dev; + spinlock_t lock; + struct list_head active; + struct list_head incoming; + unsigned int fw_output; +}; + +struct ipu7_isys_buffer { + struct list_head head; + atomic_t str2mmio_flag; +}; + +struct ipu7_isys_video_buffer { + struct vb2_v4l2_buffer vb_v4l2; + struct ipu7_isys_buffer ib; + dma_addr_t dma_addr; +}; + +#define IPU_ISYS_BUFFER_LIST_FL_INCOMING BIT(0) +#define IPU_ISYS_BUFFER_LIST_FL_ACTIVE BIT(1) +#define IPU_ISYS_BUFFER_LIST_FL_SET_STATE BIT(2) + +struct ipu7_isys_buffer_list { + struct list_head head; + unsigned int nbufs; +}; + +#define vb2_queue_to_isys_queue(__vb2) \ + container_of(__vb2, struct ipu7_isys_queue, vbq) + +#define ipu7_isys_to_isys_video_buffer(__ib) \ + container_of(__ib, struct ipu7_isys_video_buffer, ib) + +#define vb2_buffer_to_ipu7_isys_video_buffer(__vvb) \ + container_of(__vvb, struct ipu7_isys_video_buffer, vb_v4l2) + +#define ipu7_isys_buffer_to_vb2_buffer(__ib) \ + (&ipu7_isys_to_isys_video_buffer(__ib)->vb_v4l2.vb2_buf) + +void ipu7_isys_buffer_list_queue(struct ipu7_isys_buffer_list *bl, + unsigned long op_flags, + enum vb2_buffer_state state); +void ipu7_isys_buffer_to_fw_frame_buff(struct ipu7_insys_buffset *set, + struct ipu7_isys_stream *stream, + struct ipu7_isys_buffer_list *bl); +void ipu7_isys_queue_buf_ready(struct ipu7_isys_stream *stream, + struct ipu7_insys_resp *info); +int ipu7_isys_queue_init(struct ipu7_isys_queue *aq); +#endif /* IPU7_ISYS_QUEUE_H */ diff --git a/drivers/staging/media/ipu7/ipu7-isys-subdev.c b/drivers/staging/media/ipu7/ipu7-isys-subdev.c new file mode 100644 index 0000000000000..98b6ef6a2f21d --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys-subdev.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <linux/bug.h> +#include <linux/device.h> +#include <linux/minmax.h> +#include <linux/types.h> + +#include <media/media-entity.h> +#include <media/mipi-csi2.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-subdev.h> + +#include <uapi/linux/media-bus-format.h> + +#include "ipu7-bus.h" +#include "ipu7-isys.h" +#include "ipu7-isys-subdev.h" + +unsigned int ipu7_isys_mbus_code_to_mipi(u32 code) +{ + switch (code) { + case MEDIA_BUS_FMT_RGB565_1X16: + return MIPI_CSI2_DT_RGB565; + case MEDIA_BUS_FMT_RGB888_1X24: + return MIPI_CSI2_DT_RGB888; + case MEDIA_BUS_FMT_YUYV10_1X20: + return MIPI_CSI2_DT_YUV422_10B; + case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_YUYV8_1X16: + return MIPI_CSI2_DT_YUV422_8B; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + return MIPI_CSI2_DT_RAW12; + case MEDIA_BUS_FMT_Y10_1X10: + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + return MIPI_CSI2_DT_RAW10; + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + return MIPI_CSI2_DT_RAW8; + default: + WARN_ON(1); + return 0xff; + } +} + +bool ipu7_isys_is_bayer_format(u32 code) +{ + switch (ipu7_isys_mbus_code_to_mipi(code)) { + case MIPI_CSI2_DT_RAW8: + case MIPI_CSI2_DT_RAW10: + case MIPI_CSI2_DT_RAW12: + case MIPI_CSI2_DT_RAW14: + case MIPI_CSI2_DT_RAW16: + case MIPI_CSI2_DT_RAW20: + case MIPI_CSI2_DT_RAW24: + case MIPI_CSI2_DT_RAW28: + return true; + default: + return false; + } +} + +u32 ipu7_isys_convert_bayer_order(u32 code, int x, int y) +{ + static const u32 code_map[] = { + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SRGGB12_1X12, + MEDIA_BUS_FMT_SGRBG12_1X12, + MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_SBGGR12_1X12, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(code_map); i++) + if (code_map[i] == code) + break; + + if (WARN_ON(i == ARRAY_SIZE(code_map))) + return code; + + return code_map[i ^ ((((u32)y & 1U) << 1U) | ((u32)x & 1U))]; +} + +int ipu7_isys_subdev_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd); + u32 code = asd->supported_codes[0]; + struct v4l2_mbus_framefmt *fmt; + u32 other_pad, other_stream; + struct v4l2_rect *crop; + unsigned int i; + int ret; + + /* No transcoding, source and sink formats must match. */ + if ((sd->entity.pads[format->pad].flags & MEDIA_PAD_FL_SOURCE) && + sd->entity.num_pads > 1) + return v4l2_subdev_get_fmt(sd, state, format); + + format->format.width = clamp(format->format.width, IPU_ISYS_MIN_WIDTH, + IPU_ISYS_MAX_WIDTH); + format->format.height = clamp(format->format.height, + IPU_ISYS_MIN_HEIGHT, + IPU_ISYS_MAX_HEIGHT); + + for (i = 0; asd->supported_codes[i]; i++) { + if (asd->supported_codes[i] == format->format.code) { + code = asd->supported_codes[i]; + break; + } + } + format->format.code = code; + format->format.field = V4L2_FIELD_NONE; + + /* Store the format and propagate it to the source pad. */ + fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream); + if (!fmt) + return -EINVAL; + + *fmt = format->format; + + if (!(sd->entity.pads[format->pad].flags & MEDIA_PAD_FL_SINK)) + return 0; + + /* propagate format to following source pad */ + fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad, + format->stream); + if (!fmt) + return -EINVAL; + + *fmt = format->format; + + ret = v4l2_subdev_routing_find_opposite_end(&state->routing, + format->pad, + format->stream, + &other_pad, + &other_stream); + if (ret) + return -EINVAL; + + crop = v4l2_subdev_state_get_crop(state, other_pad, other_stream); + /* reset crop */ + crop->left = 0; + crop->top = 0; + crop->width = fmt->width; + crop->height = fmt->height; + + return 0; +} + +int ipu7_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct ipu7_isys_subdev *asd = to_ipu7_isys_subdev(sd); + const u32 *supported_codes = asd->supported_codes; + u32 index; + + for (index = 0; supported_codes[index]; index++) { + if (index == code->index) { + code->code = supported_codes[index]; + return 0; + } + } + + return -EINVAL; +} + +static int subdev_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_krouting *routing) +{ + static const struct v4l2_mbus_framefmt fmt = { + .width = 4096, + .height = 3072, + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .field = V4L2_FIELD_NONE, + }; + int ret; + + ret = v4l2_subdev_routing_validate(sd, routing, + V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); + if (ret) + return ret; + + return v4l2_subdev_set_routing_with_fmt(sd, state, routing, &fmt); +} + +int ipu7_isys_get_stream_pad_fmt(struct v4l2_subdev *sd, u32 pad, u32 stream, + struct v4l2_mbus_framefmt *format) +{ + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *fmt; + + if (!sd || !format) + return -EINVAL; + + state = v4l2_subdev_lock_and_get_active_state(sd); + fmt = v4l2_subdev_state_get_format(state, pad, stream); + if (fmt) + *format = *fmt; + v4l2_subdev_unlock_state(state); + + return fmt ? 0 : -EINVAL; +} + +u32 ipu7_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad) +{ + struct v4l2_subdev_state *state; + struct v4l2_subdev_route *routes; + u32 source_stream = 0; + unsigned int i; + + state = v4l2_subdev_lock_and_get_active_state(sd); + if (!state) + return 0; + + routes = state->routing.routes; + for (i = 0; i < state->routing.num_routes; i++) { + if (routes[i].source_pad == pad) { + source_stream = routes[i].source_stream; + break; + } + } + + v4l2_subdev_unlock_state(state); + + return source_stream; +} + +static int ipu7_isys_subdev_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route route = { + .sink_pad = 0, + .sink_stream = 0, + .source_pad = 1, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }; + struct v4l2_subdev_krouting routing = { + .num_routes = 1, + .routes = &route, + }; + + return subdev_set_routing(sd, state, &routing); +} + +int ipu7_isys_subdev_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + return subdev_set_routing(sd, state, routing); +} + +static const struct v4l2_subdev_internal_ops ipu7_isys_subdev_internal_ops = { + .init_state = ipu7_isys_subdev_init_state, +}; + +int ipu7_isys_subdev_init(struct ipu7_isys_subdev *asd, + const struct v4l2_subdev_ops *ops, + unsigned int nr_ctrls, + unsigned int num_sink_pads, + unsigned int num_source_pads) +{ + unsigned int num_pads = num_sink_pads + num_source_pads; + unsigned int i; + int ret; + + v4l2_subdev_init(&asd->sd, ops); + + asd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS | + V4L2_SUBDEV_FL_STREAMS; + asd->sd.owner = THIS_MODULE; + asd->sd.dev = &asd->isys->adev->auxdev.dev; + asd->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + asd->sd.internal_ops = &ipu7_isys_subdev_internal_ops; + + asd->pad = devm_kcalloc(&asd->isys->adev->auxdev.dev, num_pads, + sizeof(*asd->pad), GFP_KERNEL); + if (!asd->pad) + return -ENOMEM; + + for (i = 0; i < num_sink_pads; i++) + asd->pad[i].flags = MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_MUST_CONNECT; + + for (i = num_sink_pads; i < num_pads; i++) + asd->pad[i].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&asd->sd.entity, num_pads, asd->pad); + if (ret) { + pr_err("isys subdev init failed %d.\n", ret); + return ret; + } + + if (asd->ctrl_init) { + ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, nr_ctrls); + if (ret) + goto out_media_entity_cleanup; + + asd->ctrl_init(&asd->sd); + if (asd->ctrl_handler.error) { + ret = asd->ctrl_handler.error; + goto out_v4l2_ctrl_handler_free; + } + + asd->sd.ctrl_handler = &asd->ctrl_handler; + } + + asd->source = -1; + + return 0; + +out_v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(&asd->ctrl_handler); + +out_media_entity_cleanup: + media_entity_cleanup(&asd->sd.entity); + + return ret; +} + +void ipu7_isys_subdev_cleanup(struct ipu7_isys_subdev *asd) +{ + media_entity_cleanup(&asd->sd.entity); + v4l2_ctrl_handler_free(&asd->ctrl_handler); +} diff --git a/drivers/staging/media/ipu7/ipu7-isys-subdev.h b/drivers/staging/media/ipu7/ipu7-isys-subdev.h new file mode 100644 index 0000000000000..1057ec39ae39a --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys-subdev.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#ifndef IPU7_ISYS_SUBDEV_H +#define IPU7_ISYS_SUBDEV_H + +#include <linux/container_of.h> + +#include <media/media-entity.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-subdev.h> + +struct ipu7_isys; + +struct ipu7_isys_subdev { + struct v4l2_subdev sd; + struct ipu7_isys *isys; + u32 const *supported_codes; + struct media_pad *pad; + struct v4l2_ctrl_handler ctrl_handler; + void (*ctrl_init)(struct v4l2_subdev *sd); + int source; /* SSI stream source; -1 if unset */ +}; + +#define to_ipu7_isys_subdev(__sd) \ + container_of(__sd, struct ipu7_isys_subdev, sd) +unsigned int ipu7_isys_mbus_code_to_mipi(u32 code); +bool ipu7_isys_is_bayer_format(u32 code); +u32 ipu7_isys_convert_bayer_order(u32 code, int x, int y); + +int ipu7_isys_subdev_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format); +int ipu7_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum + *code); +u32 ipu7_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad); +int ipu7_isys_get_stream_pad_fmt(struct v4l2_subdev *sd, u32 pad, u32 stream, + struct v4l2_mbus_framefmt *format); +int ipu7_isys_subdev_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing); +int ipu7_isys_subdev_init(struct ipu7_isys_subdev *asd, + const struct v4l2_subdev_ops *ops, + unsigned int nr_ctrls, + unsigned int num_sink_pads, + unsigned int num_source_pads); +void ipu7_isys_subdev_cleanup(struct ipu7_isys_subdev *asd); +#endif /* IPU7_ISYS_SUBDEV_H */ diff --git a/drivers/staging/media/ipu7/ipu7-isys-video.c b/drivers/staging/media/ipu7/ipu7-isys-video.c new file mode 100644 index 0000000000000..8756da3a8fb0b --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys-video.c @@ -0,0 +1,1112 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <linux/align.h> +#include <linux/bits.h> +#include <linux/bug.h> +#include <linux/completion.h> +#include <linux/container_of.h> +#include <linux/compat.h> +#include <linux/device.h> +#include <linux/iopoll.h> +#include <linux/list.h> +#include <linux/minmax.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/spinlock.h> +#include <linux/string.h> + +#include <media/media-entity.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mc.h> +#include <media/v4l2-subdev.h> +#include <media/videobuf2-v4l2.h> + +#include "abi/ipu7_fw_isys_abi.h" + +#include "ipu7.h" +#include "ipu7-bus.h" +#include "ipu7-buttress-regs.h" +#include "ipu7-fw-isys.h" +#include "ipu7-isys.h" +#include "ipu7-isys-video.h" +#include "ipu7-platform-regs.h" + +const struct ipu7_isys_pixelformat ipu7_isys_pfmts[] = { + {V4L2_PIX_FMT_SBGGR12, 16, 12, MEDIA_BUS_FMT_SBGGR12_1X12, + IPU_INSYS_FRAME_FORMAT_RAW16}, + {V4L2_PIX_FMT_SGBRG12, 16, 12, MEDIA_BUS_FMT_SGBRG12_1X12, + IPU_INSYS_FRAME_FORMAT_RAW16}, + {V4L2_PIX_FMT_SGRBG12, 16, 12, MEDIA_BUS_FMT_SGRBG12_1X12, + IPU_INSYS_FRAME_FORMAT_RAW16}, + {V4L2_PIX_FMT_SRGGB12, 16, 12, MEDIA_BUS_FMT_SRGGB12_1X12, + IPU_INSYS_FRAME_FORMAT_RAW16}, + {V4L2_PIX_FMT_SBGGR10, 16, 10, MEDIA_BUS_FMT_SBGGR10_1X10, + IPU_INSYS_FRAME_FORMAT_RAW16}, + {V4L2_PIX_FMT_SGBRG10, 16, 10, MEDIA_BUS_FMT_SGBRG10_1X10, + IPU_INSYS_FRAME_FORMAT_RAW16}, + {V4L2_PIX_FMT_SGRBG10, 16, 10, MEDIA_BUS_FMT_SGRBG10_1X10, + IPU_INSYS_FRAME_FORMAT_RAW16}, + {V4L2_PIX_FMT_SRGGB10, 16, 10, MEDIA_BUS_FMT_SRGGB10_1X10, + IPU_INSYS_FRAME_FORMAT_RAW16}, + {V4L2_PIX_FMT_SBGGR8, 8, 8, MEDIA_BUS_FMT_SBGGR8_1X8, + IPU_INSYS_FRAME_FORMAT_RAW8}, + {V4L2_PIX_FMT_SGBRG8, 8, 8, MEDIA_BUS_FMT_SGBRG8_1X8, + IPU_INSYS_FRAME_FORMAT_RAW8}, + {V4L2_PIX_FMT_SGRBG8, 8, 8, MEDIA_BUS_FMT_SGRBG8_1X8, + IPU_INSYS_FRAME_FORMAT_RAW8}, + {V4L2_PIX_FMT_SRGGB8, 8, 8, MEDIA_BUS_FMT_SRGGB8_1X8, + IPU_INSYS_FRAME_FORMAT_RAW8}, + {V4L2_PIX_FMT_SBGGR12P, 12, 12, MEDIA_BUS_FMT_SBGGR12_1X12, + IPU_INSYS_FRAME_FORMAT_RAW12}, + {V4L2_PIX_FMT_SGBRG12P, 12, 12, MEDIA_BUS_FMT_SGBRG12_1X12, + IPU_INSYS_FRAME_FORMAT_RAW12}, + {V4L2_PIX_FMT_SGRBG12P, 12, 12, MEDIA_BUS_FMT_SGRBG12_1X12, + IPU_INSYS_FRAME_FORMAT_RAW12}, + {V4L2_PIX_FMT_SRGGB12P, 12, 12, MEDIA_BUS_FMT_SRGGB12_1X12, + IPU_INSYS_FRAME_FORMAT_RAW12}, + {V4L2_PIX_FMT_SBGGR10P, 10, 10, MEDIA_BUS_FMT_SBGGR10_1X10, + IPU_INSYS_FRAME_FORMAT_RAW10}, + {V4L2_PIX_FMT_SGBRG10P, 10, 10, MEDIA_BUS_FMT_SGBRG10_1X10, + IPU_INSYS_FRAME_FORMAT_RAW10}, + {V4L2_PIX_FMT_SGRBG10P, 10, 10, MEDIA_BUS_FMT_SGRBG10_1X10, + IPU_INSYS_FRAME_FORMAT_RAW10}, + {V4L2_PIX_FMT_SRGGB10P, 10, 10, MEDIA_BUS_FMT_SRGGB10_1X10, + IPU_INSYS_FRAME_FORMAT_RAW10}, + {V4L2_PIX_FMT_UYVY, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16, + IPU_INSYS_FRAME_FORMAT_UYVY}, + {V4L2_PIX_FMT_YUYV, 16, 16, MEDIA_BUS_FMT_YUYV8_1X16, + IPU_INSYS_FRAME_FORMAT_YUYV}, + {V4L2_PIX_FMT_RGB565, 16, 16, MEDIA_BUS_FMT_RGB565_1X16, + IPU_INSYS_FRAME_FORMAT_RGB565}, + {V4L2_PIX_FMT_BGR24, 24, 24, MEDIA_BUS_FMT_RGB888_1X24, + IPU_INSYS_FRAME_FORMAT_RGBA888}, +}; + +static int video_open(struct file *file) +{ + return v4l2_fh_open(file); +} + +const struct ipu7_isys_pixelformat *ipu7_isys_get_isys_format(u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ipu7_isys_pfmts); i++) { + const struct ipu7_isys_pixelformat *pfmt = &ipu7_isys_pfmts[i]; + + if (pfmt->pixelformat == pixelformat) + return pfmt; + } + + return &ipu7_isys_pfmts[0]; +} + +static int ipu7_isys_vidioc_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct ipu7_isys_video *av = video_drvdata(file); + + strscpy(cap->driver, IPU_ISYS_NAME, sizeof(cap->driver)); + strscpy(cap->card, av->isys->media_dev.model, sizeof(cap->card)); + + return 0; +} + +static int ipu7_isys_vidioc_enum_fmt(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + unsigned int i, num_found; + + for (i = 0, num_found = 0; i < ARRAY_SIZE(ipu7_isys_pfmts); i++) { + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + continue; + + if (f->mbus_code && f->mbus_code != ipu7_isys_pfmts[i].code) + continue; + + if (num_found < f->index) { + num_found++; + continue; + } + + f->flags = 0; + f->pixelformat = ipu7_isys_pfmts[i].pixelformat; + + return 0; + } + + return -EINVAL; +} + +static int ipu7_isys_vidioc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + unsigned int i; + + if (fsize->index > 0) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(ipu7_isys_pfmts); i++) { + if (fsize->pixel_format != ipu7_isys_pfmts[i].pixelformat) + continue; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = IPU_ISYS_MIN_WIDTH; + fsize->stepwise.max_width = IPU_ISYS_MAX_WIDTH; + fsize->stepwise.min_height = IPU_ISYS_MIN_HEIGHT; + fsize->stepwise.max_height = IPU_ISYS_MAX_HEIGHT; + fsize->stepwise.step_width = 2; + fsize->stepwise.step_height = 2; + + return 0; + } + + return -EINVAL; +} + +static int ipu7_isys_vidioc_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct ipu7_isys_video *av = video_drvdata(file); + + f->fmt.pix = av->pix_fmt; + + return 0; +} + +static void ipu7_isys_try_fmt_cap(struct ipu7_isys_video *av, u32 type, + u32 *format, u32 *width, u32 *height, + u32 *bytesperline, u32 *sizeimage) +{ + const struct ipu7_isys_pixelformat *pfmt = + ipu7_isys_get_isys_format(*format); + + *format = pfmt->pixelformat; + *width = clamp(*width, IPU_ISYS_MIN_WIDTH, IPU_ISYS_MAX_WIDTH); + *height = clamp(*height, IPU_ISYS_MIN_HEIGHT, IPU_ISYS_MAX_HEIGHT); + + if (pfmt->bpp != pfmt->bpp_packed) + *bytesperline = *width * DIV_ROUND_UP(pfmt->bpp, BITS_PER_BYTE); + else + *bytesperline = DIV_ROUND_UP(*width * pfmt->bpp, BITS_PER_BYTE); + + *bytesperline = ALIGN(*bytesperline, 64U); + + /* + * (height + 1) * bytesperline due to a hardware issue: the DMA unit + * is a power of two, and a line should be transferred as few units + * as possible. The result is that up to line length more data than + * the image size may be transferred to memory after the image. + * Another limitation is the GDA allocation unit size. For low + * resolution it gives a bigger number. Use larger one to avoid + * memory corruption. + */ + *sizeimage = *bytesperline * *height + + max(*bytesperline, + av->isys->pdata->ipdata->isys_dma_overshoot); +} + +static void __ipu_isys_vidioc_try_fmt_vid_cap(struct ipu7_isys_video *av, + struct v4l2_format *f) +{ + ipu7_isys_try_fmt_cap(av, f->type, &f->fmt.pix.pixelformat, + &f->fmt.pix.width, &f->fmt.pix.height, + &f->fmt.pix.bytesperline, &f->fmt.pix.sizeimage); + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.colorspace = V4L2_COLORSPACE_RAW; + f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix.quantization = V4L2_QUANTIZATION_DEFAULT; + f->fmt.pix.xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + +static int ipu7_isys_vidioc_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct ipu7_isys_video *av = video_drvdata(file); + + if (vb2_is_busy(&av->aq.vbq)) + return -EBUSY; + + __ipu_isys_vidioc_try_fmt_vid_cap(av, f); + + return 0; +} + +static int ipu7_isys_vidioc_s_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct ipu7_isys_video *av = video_drvdata(file); + + ipu7_isys_vidioc_try_fmt_vid_cap(file, fh, f); + av->pix_fmt = f->fmt.pix; + + return 0; +} + +static int ipu7_isys_vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct ipu7_isys_video *av = video_drvdata(file); + int ret; + + av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->type); + av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->type); + + ret = vb2_queue_change_type(&av->aq.vbq, p->type); + if (ret) + return ret; + + return vb2_ioctl_reqbufs(file, priv, p); +} + +static int ipu7_isys_vidioc_create_bufs(struct file *file, void *priv, + struct v4l2_create_buffers *p) +{ + struct ipu7_isys_video *av = video_drvdata(file); + int ret; + + av->aq.vbq.is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(p->format.type); + av->aq.vbq.is_output = V4L2_TYPE_IS_OUTPUT(p->format.type); + + ret = vb2_queue_change_type(&av->aq.vbq, p->format.type); + if (ret) + return ret; + + return vb2_ioctl_create_bufs(file, priv, p); +} + +static int link_validate(struct media_link *link) +{ + struct ipu7_isys_video *av = + container_of(link->sink, struct ipu7_isys_video, pad); + struct device *dev = &av->isys->adev->auxdev.dev; + struct v4l2_subdev_state *s_state; + struct v4l2_mbus_framefmt *s_fmt; + struct v4l2_subdev *s_sd; + struct media_pad *s_pad; + u32 s_stream, code; + int ret = -EPIPE; + + if (!link->source->entity) + return ret; + + s_sd = media_entity_to_v4l2_subdev(link->source->entity); + s_state = v4l2_subdev_get_unlocked_active_state(s_sd); + if (!s_state) + return ret; + + dev_dbg(dev, "validating link \"%s\":%u -> \"%s\"\n", + link->source->entity->name, link->source->index, + link->sink->entity->name); + + s_pad = media_pad_remote_pad_first(&av->pad); + s_stream = ipu7_isys_get_src_stream_by_src_pad(s_sd, s_pad->index); + + v4l2_subdev_lock_state(s_state); + + s_fmt = v4l2_subdev_state_get_format(s_state, s_pad->index, s_stream); + if (!s_fmt) { + dev_err(dev, "failed to get source pad format\n"); + goto unlock; + } + + code = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat)->code; + + if (s_fmt->width != av->pix_fmt.width || + s_fmt->height != av->pix_fmt.height || s_fmt->code != code) { + dev_dbg(dev, "format mismatch %dx%d,%x != %dx%d,%x\n", + s_fmt->width, s_fmt->height, s_fmt->code, + av->pix_fmt.width, av->pix_fmt.height, code); + goto unlock; + } + + v4l2_subdev_unlock_state(s_state); + + return 0; +unlock: + v4l2_subdev_unlock_state(s_state); + + return ret; +} + +static void get_stream_opened(struct ipu7_isys_video *av) +{ + unsigned long flags; + + spin_lock_irqsave(&av->isys->streams_lock, flags); + av->isys->stream_opened++; + spin_unlock_irqrestore(&av->isys->streams_lock, flags); +} + +static void put_stream_opened(struct ipu7_isys_video *av) +{ + unsigned long flags; + + spin_lock_irqsave(&av->isys->streams_lock, flags); + av->isys->stream_opened--; + spin_unlock_irqrestore(&av->isys->streams_lock, flags); +} + +static int ipu7_isys_fw_pin_cfg(struct ipu7_isys_video *av, + struct ipu7_insys_stream_cfg *cfg) +{ + struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad); + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity); + struct ipu7_isys_stream *stream = av->stream; + const struct ipu7_isys_pixelformat *pfmt = + ipu7_isys_get_isys_format(av->pix_fmt.pixelformat); + struct ipu7_insys_output_pin *output_pin; + struct ipu7_insys_input_pin *input_pin; + int input_pins = cfg->nof_input_pins++; + struct ipu7_isys_queue *aq = &av->aq; + struct ipu7_isys *isys = av->isys; + struct device *dev = &isys->adev->auxdev.dev; + struct v4l2_mbus_framefmt fmt; + int output_pins; + u32 src_stream; + int ret; + + src_stream = ipu7_isys_get_src_stream_by_src_pad(sd, src_pad->index); + ret = ipu7_isys_get_stream_pad_fmt(sd, src_pad->index, src_stream, + &fmt); + if (ret < 0) { + dev_err(dev, "can't get stream format (%d)\n", ret); + return ret; + } + + input_pin = &cfg->input_pins[input_pins]; + input_pin->input_res.width = fmt.width; + input_pin->input_res.height = fmt.height; + input_pin->dt = av->dt; + input_pin->disable_mipi_unpacking = 0; + pfmt = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat); + if (pfmt->bpp == pfmt->bpp_packed && pfmt->bpp % BITS_PER_BYTE) + input_pin->disable_mipi_unpacking = 1; + input_pin->mapped_dt = N_IPU_INSYS_MIPI_DATA_TYPE; + input_pin->dt_rename_mode = IPU_INSYS_MIPI_DT_NO_RENAME; + /* if enable polling isys interrupt, the follow values maybe set */ + input_pin->sync_msg_map = IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF | + IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED | + IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF | + IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED; + + output_pins = cfg->nof_output_pins++; + aq->fw_output = output_pins; + stream->output_pins[output_pins].pin_ready = ipu7_isys_queue_buf_ready; + stream->output_pins[output_pins].aq = aq; + + output_pin = &cfg->output_pins[output_pins]; + /* output pin msg link */ + output_pin->link.buffer_lines = 0; + output_pin->link.foreign_key = IPU_MSG_LINK_FOREIGN_KEY_NONE; + output_pin->link.granularity_pointer_update = 0; + output_pin->link.msg_link_streaming_mode = + IA_GOFO_MSG_LINK_STREAMING_MODE_SOFF; + + output_pin->link.pbk_id = IPU_MSG_LINK_PBK_ID_DONT_CARE; + output_pin->link.pbk_slot_id = IPU_MSG_LINK_PBK_SLOT_ID_DONT_CARE; + output_pin->link.dest = IPU_INSYS_OUTPUT_LINK_DEST_MEM; + output_pin->link.use_sw_managed = 1; + /* TODO: set the snoop bit for metadata capture */ + output_pin->link.is_snoop = 0; + + /* output pin crop */ + output_pin->crop.line_top = 0; + output_pin->crop.line_bottom = 0; + + /* output de-compression */ + output_pin->dpcm.enable = 0; + + /* frame format type */ + pfmt = ipu7_isys_get_isys_format(av->pix_fmt.pixelformat); + output_pin->ft = (u16)pfmt->css_pixelformat; + + /* stride in bytes */ + output_pin->stride = av->pix_fmt.bytesperline; + output_pin->send_irq = 1; + output_pin->early_ack_en = 0; + + /* input pin id */ + output_pin->input_pin_id = input_pins; + + return 0; +} + +/* Create stream and start it using the CSS FW ABI. */ +static int start_stream_firmware(struct ipu7_isys_video *av, + struct ipu7_isys_buffer_list *bl) +{ + struct device *dev = &av->isys->adev->auxdev.dev; + struct ipu7_isys_stream *stream = av->stream; + struct ipu7_insys_stream_cfg *stream_cfg; + struct ipu7_insys_buffset *buf = NULL; + struct isys_fw_msgs *msg = NULL; + struct ipu7_isys_queue *aq; + int ret, retout, tout; + u16 send_type; + + if (WARN_ON(!bl)) + return -EIO; + + msg = ipu7_get_fw_msg_buf(stream); + if (!msg) + return -ENOMEM; + + stream_cfg = &msg->fw_msg.stream; + stream_cfg->port_id = stream->stream_source; + stream_cfg->vc = stream->vc; + stream_cfg->stream_msg_map = IPU_INSYS_STREAM_ENABLE_MSG_SEND_RESP | + IPU_INSYS_STREAM_ENABLE_MSG_SEND_IRQ; + + list_for_each_entry(aq, &stream->queues, node) { + struct ipu7_isys_video *__av = ipu7_isys_queue_to_video(aq); + + ret = ipu7_isys_fw_pin_cfg(__av, stream_cfg); + if (ret < 0) { + ipu7_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg); + return ret; + } + } + + ipu7_fw_isys_dump_stream_cfg(dev, stream_cfg); + + stream->nr_output_pins = stream_cfg->nof_output_pins; + + reinit_completion(&stream->stream_open_completion); + + ret = ipu7_fw_isys_complex_cmd(av->isys, stream->stream_handle, + stream_cfg, msg->dma_addr, + sizeof(*stream_cfg), + IPU_INSYS_SEND_TYPE_STREAM_OPEN); + if (ret < 0) { + dev_err(dev, "can't open stream (%d)\n", ret); + ipu7_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg); + return ret; + } + + get_stream_opened(av); + + tout = wait_for_completion_timeout(&stream->stream_open_completion, + FW_CALL_TIMEOUT_JIFFIES); + + ipu7_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg); + + if (!tout) { + dev_err(dev, "stream open time out\n"); + ret = -ETIMEDOUT; + goto out_put_stream_opened; + } + if (stream->error) { + dev_err(dev, "stream open error: %d\n", stream->error); + ret = -EIO; + goto out_put_stream_opened; + } + dev_dbg(dev, "start stream: open complete\n"); + + msg = ipu7_get_fw_msg_buf(stream); + if (!msg) { + ret = -ENOMEM; + goto out_put_stream_opened; + } + buf = &msg->fw_msg.frame; + + ipu7_isys_buffer_to_fw_frame_buff(buf, stream, bl); + ipu7_isys_buffer_list_queue(bl, IPU_ISYS_BUFFER_LIST_FL_ACTIVE, 0); + + reinit_completion(&stream->stream_start_completion); + + send_type = IPU_INSYS_SEND_TYPE_STREAM_START_AND_CAPTURE; + ipu7_fw_isys_dump_frame_buff_set(dev, buf, + stream_cfg->nof_output_pins); + ret = ipu7_fw_isys_complex_cmd(av->isys, stream->stream_handle, buf, + msg->dma_addr, sizeof(*buf), + send_type); + if (ret < 0) { + dev_err(dev, "can't start streaming (%d)\n", ret); + goto out_stream_close; + } + + tout = wait_for_completion_timeout(&stream->stream_start_completion, + FW_CALL_TIMEOUT_JIFFIES); + if (!tout) { + dev_err(dev, "stream start time out\n"); + ret = -ETIMEDOUT; + goto out_stream_close; + } + if (stream->error) { + dev_err(dev, "stream start error: %d\n", stream->error); + ret = -EIO; + goto out_stream_close; + } + dev_dbg(dev, "start stream: complete\n"); + + return 0; + +out_stream_close: + reinit_completion(&stream->stream_close_completion); + + retout = ipu7_fw_isys_simple_cmd(av->isys, stream->stream_handle, + IPU_INSYS_SEND_TYPE_STREAM_CLOSE); + if (retout < 0) { + dev_dbg(dev, "can't close stream (%d)\n", retout); + goto out_put_stream_opened; + } + + tout = wait_for_completion_timeout(&stream->stream_close_completion, + FW_CALL_TIMEOUT_JIFFIES); + if (!tout) + dev_err(dev, "stream close time out with error %d\n", + stream->error); + else + dev_dbg(dev, "stream close complete\n"); + +out_put_stream_opened: + put_stream_opened(av); + + return ret; +} + +static void stop_streaming_firmware(struct ipu7_isys_video *av) +{ + struct device *dev = &av->isys->adev->auxdev.dev; + struct ipu7_isys_stream *stream = av->stream; + int ret, tout; + + reinit_completion(&stream->stream_stop_completion); + + ret = ipu7_fw_isys_simple_cmd(av->isys, stream->stream_handle, + IPU_INSYS_SEND_TYPE_STREAM_FLUSH); + if (ret < 0) { + dev_err(dev, "can't stop stream (%d)\n", ret); + return; + } + + tout = wait_for_completion_timeout(&stream->stream_stop_completion, + FW_CALL_TIMEOUT_JIFFIES); + if (!tout) + dev_warn(dev, "stream stop time out\n"); + else if (stream->error) + dev_warn(dev, "stream stop error: %d\n", stream->error); + else + dev_dbg(dev, "stop stream: complete\n"); +} + +static void close_streaming_firmware(struct ipu7_isys_video *av) +{ + struct device *dev = &av->isys->adev->auxdev.dev; + struct ipu7_isys_stream *stream = av->stream; + int ret, tout; + + reinit_completion(&stream->stream_close_completion); + + ret = ipu7_fw_isys_simple_cmd(av->isys, stream->stream_handle, + IPU_INSYS_SEND_TYPE_STREAM_CLOSE); + if (ret < 0) { + dev_err(dev, "can't close stream (%d)\n", ret); + return; + } + + tout = wait_for_completion_timeout(&stream->stream_close_completion, + FW_CALL_TIMEOUT_JIFFIES); + if (!tout) + dev_warn(dev, "stream close time out\n"); + else if (stream->error) + dev_warn(dev, "stream close error: %d\n", stream->error); + else + dev_dbg(dev, "close stream: complete\n"); + + put_stream_opened(av); +} + +int ipu7_isys_video_prepare_stream(struct ipu7_isys_video *av, + struct media_entity *source_entity, + int nr_queues) +{ + struct ipu7_isys_stream *stream = av->stream; + struct ipu7_isys_csi2 *csi2; + + if (WARN_ON(stream->nr_streaming)) + return -EINVAL; + + stream->nr_queues = nr_queues; + atomic_set(&stream->sequence, 0); + atomic_set(&stream->buf_id, 0); + + stream->seq_index = 0; + memset(stream->seq, 0, sizeof(stream->seq)); + + if (WARN_ON(!list_empty(&stream->queues))) + return -EINVAL; + + stream->stream_source = stream->asd->source; + + csi2 = ipu7_isys_subdev_to_csi2(stream->asd); + csi2->receiver_errors = 0; + stream->source_entity = source_entity; + + dev_dbg(&av->isys->adev->auxdev.dev, + "prepare stream: external entity %s\n", + stream->source_entity->name); + + return 0; +} + +void ipu7_isys_put_stream(struct ipu7_isys_stream *stream) +{ + unsigned long flags; + struct device *dev; + unsigned int i; + + if (!stream) { + pr_err("ipu7-isys: no available stream\n"); + return; + } + + dev = &stream->isys->adev->auxdev.dev; + + spin_lock_irqsave(&stream->isys->streams_lock, flags); + for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) { + if (&stream->isys->streams[i] == stream) { + if (stream->isys->streams_ref_count[i] > 0) + stream->isys->streams_ref_count[i]--; + else + dev_warn(dev, "invalid stream %d\n", i); + + break; + } + } + spin_unlock_irqrestore(&stream->isys->streams_lock, flags); +} + +static struct ipu7_isys_stream * +ipu7_isys_get_stream(struct ipu7_isys_video *av, struct ipu7_isys_subdev *asd) +{ + struct ipu7_isys_stream *stream = NULL; + struct ipu7_isys *isys = av->isys; + unsigned long flags; + unsigned int i; + u8 vc = av->vc; + + if (!isys) + return NULL; + + spin_lock_irqsave(&isys->streams_lock, flags); + for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) { + if (isys->streams_ref_count[i] && isys->streams[i].vc == vc && + isys->streams[i].asd == asd) { + isys->streams_ref_count[i]++; + stream = &isys->streams[i]; + break; + } + } + + if (!stream) { + for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) { + if (!isys->streams_ref_count[i]) { + isys->streams_ref_count[i]++; + stream = &isys->streams[i]; + stream->vc = vc; + stream->asd = asd; + break; + } + } + } + spin_unlock_irqrestore(&isys->streams_lock, flags); + + return stream; +} + +struct ipu7_isys_stream * +ipu7_isys_query_stream_by_handle(struct ipu7_isys *isys, u8 stream_handle) +{ + unsigned long flags; + struct ipu7_isys_stream *stream = NULL; + + if (!isys) + return NULL; + + if (stream_handle >= IPU_ISYS_MAX_STREAMS) { + dev_err(&isys->adev->auxdev.dev, + "stream_handle %d is invalid\n", stream_handle); + return NULL; + } + + spin_lock_irqsave(&isys->streams_lock, flags); + if (isys->streams_ref_count[stream_handle] > 0) { + isys->streams_ref_count[stream_handle]++; + stream = &isys->streams[stream_handle]; + } + spin_unlock_irqrestore(&isys->streams_lock, flags); + + return stream; +} + +struct ipu7_isys_stream * +ipu7_isys_query_stream_by_source(struct ipu7_isys *isys, int source, u8 vc) +{ + struct ipu7_isys_stream *stream = NULL; + unsigned long flags; + unsigned int i; + + if (!isys) + return NULL; + + if (source < 0) { + dev_err(&isys->adev->auxdev.dev, + "query stream with invalid port number\n"); + return NULL; + } + + spin_lock_irqsave(&isys->streams_lock, flags); + for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) { + if (!isys->streams_ref_count[i]) + continue; + + if (isys->streams[i].stream_source == source && + isys->streams[i].vc == vc) { + stream = &isys->streams[i]; + isys->streams_ref_count[i]++; + break; + } + } + spin_unlock_irqrestore(&isys->streams_lock, flags); + + return stream; +} + +static u32 get_remote_pad_stream(struct media_pad *r_pad) +{ + struct v4l2_subdev_state *state; + struct v4l2_subdev *sd; + u32 stream_id = 0; + unsigned int i; + + sd = media_entity_to_v4l2_subdev(r_pad->entity); + state = v4l2_subdev_lock_and_get_active_state(sd); + if (!state) + return 0; + + for (i = 0; i < state->stream_configs.num_configs; i++) { + struct v4l2_subdev_stream_config *cfg = + &state->stream_configs.configs[i]; + if (cfg->pad == r_pad->index) { + stream_id = cfg->stream; + break; + } + } + + v4l2_subdev_unlock_state(state); + + return stream_id; +} + +int ipu7_isys_video_set_streaming(struct ipu7_isys_video *av, int state, + struct ipu7_isys_buffer_list *bl) +{ + struct ipu7_isys_stream *stream = av->stream; + struct device *dev = &av->isys->adev->auxdev.dev; + struct media_pad *r_pad; + struct v4l2_subdev *sd; + u32 r_stream; + int ret = 0; + + dev_dbg(dev, "set stream: %d\n", state); + + if (WARN(!stream->source_entity, "No source entity for stream\n")) + return -ENODEV; + + sd = &stream->asd->sd; + r_pad = media_pad_remote_pad_first(&av->pad); + r_stream = get_remote_pad_stream(r_pad); + if (!state) { + stop_streaming_firmware(av); + + /* stop sub-device which connects with video */ + dev_dbg(dev, "disable streams %s pad:%d mask:0x%llx\n", + sd->name, r_pad->index, BIT_ULL(r_stream)); + ret = v4l2_subdev_disable_streams(sd, r_pad->index, + BIT_ULL(r_stream)); + if (ret) { + dev_err(dev, "disable streams %s failed with %d\n", + sd->name, ret); + return ret; + } + + close_streaming_firmware(av); + } else { + ret = start_stream_firmware(av, bl); + if (ret) { + dev_err(dev, "start stream of firmware failed\n"); + return ret; + } + + /* start sub-device which connects with video */ + dev_dbg(dev, "enable streams %s pad: %d mask:0x%llx\n", + sd->name, r_pad->index, BIT_ULL(r_stream)); + ret = v4l2_subdev_enable_streams(sd, r_pad->index, + BIT_ULL(r_stream)); + if (ret) { + dev_err(dev, "enable streams %s failed with %d\n", + sd->name, ret); + goto out_media_entity_stop_streaming_firmware; + } + } + + av->streaming = state; + + return 0; + +out_media_entity_stop_streaming_firmware: + stop_streaming_firmware(av); + + return ret; +} + +static const struct v4l2_ioctl_ops ipu7_v4l2_ioctl_ops = { + .vidioc_querycap = ipu7_isys_vidioc_querycap, + .vidioc_enum_fmt_vid_cap = ipu7_isys_vidioc_enum_fmt, + .vidioc_enum_framesizes = ipu7_isys_vidioc_enum_framesizes, + .vidioc_g_fmt_vid_cap = ipu7_isys_vidioc_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = ipu7_isys_vidioc_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = ipu7_isys_vidioc_try_fmt_vid_cap, + .vidioc_reqbufs = ipu7_isys_vidioc_reqbufs, + .vidioc_create_bufs = ipu7_isys_vidioc_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_expbuf = vb2_ioctl_expbuf, +}; + +static const struct media_entity_operations entity_ops = { + .link_validate = link_validate, +}; + +static const struct v4l2_file_operations isys_fops = { + .owner = THIS_MODULE, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, + .open = video_open, + .release = vb2_fop_release, +}; + +int ipu7_isys_fw_open(struct ipu7_isys *isys) +{ + struct ipu7_bus_device *adev = isys->adev; + int ret; + + ret = pm_runtime_resume_and_get(&adev->auxdev.dev); + if (ret < 0) + return ret; + + mutex_lock(&isys->mutex); + + if (isys->ref_count++) + goto unlock; + + /* + * Buffers could have been left to wrong queue at last closure. + * Move them now back to empty buffer queue. + */ + ipu7_cleanup_fw_msg_bufs(isys); + + ret = ipu7_fw_isys_open(isys); + if (ret < 0) + goto out; + +unlock: + mutex_unlock(&isys->mutex); + + return 0; +out: + isys->ref_count--; + mutex_unlock(&isys->mutex); + pm_runtime_put(&adev->auxdev.dev); + + return ret; +} + +void ipu7_isys_fw_close(struct ipu7_isys *isys) +{ + mutex_lock(&isys->mutex); + + isys->ref_count--; + + if (!isys->ref_count) + ipu7_fw_isys_close(isys); + + mutex_unlock(&isys->mutex); +} + +int ipu7_isys_setup_video(struct ipu7_isys_video *av, + struct media_entity **source_entity, int *nr_queues) +{ + const struct ipu7_isys_pixelformat *pfmt = + ipu7_isys_get_isys_format(av->pix_fmt.pixelformat); + struct device *dev = &av->isys->adev->auxdev.dev; + struct media_pad *source_pad, *remote_pad; + struct v4l2_mbus_frame_desc_entry entry; + struct v4l2_subdev_route *route = NULL; + struct v4l2_subdev_route *r; + struct v4l2_subdev_state *state; + struct ipu7_isys_subdev *asd; + struct v4l2_subdev *remote_sd; + struct media_pipeline *pipeline; + int ret = -EINVAL; + + *nr_queues = 0; + + remote_pad = media_pad_remote_pad_unique(&av->pad); + if (IS_ERR(remote_pad)) { + dev_dbg(dev, "failed to get remote pad\n"); + return PTR_ERR(remote_pad); + } + + remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); + asd = to_ipu7_isys_subdev(remote_sd); + + source_pad = media_pad_remote_pad_first(&remote_pad->entity->pads[0]); + if (!source_pad) { + dev_dbg(dev, "No external source entity\n"); + return -ENODEV; + } + + *source_entity = source_pad->entity; + + state = v4l2_subdev_lock_and_get_active_state(remote_sd); + for_each_active_route(&state->routing, r) { + if (r->source_pad == remote_pad->index) + route = r; + } + + if (!route) { + v4l2_subdev_unlock_state(state); + dev_dbg(dev, "Failed to find route\n"); + return -ENODEV; + } + + v4l2_subdev_unlock_state(state); + + ret = ipu7_isys_csi2_get_remote_desc(route->sink_stream, + to_ipu7_isys_csi2(asd), + *source_entity, &entry, + nr_queues); + if (ret == -ENOIOCTLCMD) { + av->vc = 0; + av->dt = ipu7_isys_mbus_code_to_mipi(pfmt->code); + if (av->dt == 0xff) + return -EINVAL; + *nr_queues = 1; + } else if (*nr_queues && !ret) { + dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n", + entry.stream, entry.length, entry.bus.csi2.vc, + entry.bus.csi2.dt); + + av->vc = entry.bus.csi2.vc; + av->dt = entry.bus.csi2.dt; + } else { + dev_err(dev, "failed to get remote frame desc\n"); + return ret; + } + + pipeline = media_entity_pipeline(&av->vdev.entity); + if (!pipeline) + ret = video_device_pipeline_alloc_start(&av->vdev); + else + ret = video_device_pipeline_start(&av->vdev, pipeline); + if (ret < 0) { + dev_dbg(dev, "media pipeline start failed\n"); + return ret; + } + + av->stream = ipu7_isys_get_stream(av, asd); + if (!av->stream) { + video_device_pipeline_stop(&av->vdev); + dev_err(dev, "no available stream for firmware\n"); + return -EINVAL; + } + + return 0; +} + +/* + * Do everything that's needed to initialise things related to video + * buffer queue, video node, and the related media entity. The caller + * is expected to assign isys field and set the name of the video + * device. + */ +int ipu7_isys_video_init(struct ipu7_isys_video *av) +{ + struct v4l2_format format = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .fmt.pix = { + .width = 1920, + .height = 1080, + }, + }; + int ret; + + mutex_init(&av->mutex); + av->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_IO_MC | + V4L2_CAP_VIDEO_CAPTURE; + av->vdev.vfl_dir = VFL_DIR_RX; + + ret = ipu7_isys_queue_init(&av->aq); + if (ret) + goto out_mutex_destroy; + + av->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; + ret = media_entity_pads_init(&av->vdev.entity, 1, &av->pad); + if (ret) + goto out_vb2_queue_cleanup; + + av->vdev.entity.ops = &entity_ops; + av->vdev.release = video_device_release_empty; + av->vdev.fops = &isys_fops; + av->vdev.v4l2_dev = &av->isys->v4l2_dev; + av->vdev.dev_parent = &av->isys->adev->isp->pdev->dev; + av->vdev.ioctl_ops = &ipu7_v4l2_ioctl_ops; + av->vdev.queue = &av->aq.vbq; + av->vdev.lock = &av->mutex; + + __ipu_isys_vidioc_try_fmt_vid_cap(av, &format); + av->pix_fmt = format.fmt.pix; + + set_bit(V4L2_FL_USES_V4L2_FH, &av->vdev.flags); + video_set_drvdata(&av->vdev, av); + + ret = video_register_device(&av->vdev, VFL_TYPE_VIDEO, -1); + if (ret) + goto out_media_entity_cleanup; + + return ret; + +out_media_entity_cleanup: + vb2_video_unregister_device(&av->vdev); + media_entity_cleanup(&av->vdev.entity); + +out_vb2_queue_cleanup: + vb2_queue_release(&av->aq.vbq); + +out_mutex_destroy: + mutex_destroy(&av->mutex); + + return ret; +} + +void ipu7_isys_video_cleanup(struct ipu7_isys_video *av) +{ + vb2_video_unregister_device(&av->vdev); + media_entity_cleanup(&av->vdev.entity); + mutex_destroy(&av->mutex); +} diff --git a/drivers/staging/media/ipu7/ipu7-isys-video.h b/drivers/staging/media/ipu7/ipu7-isys-video.h new file mode 100644 index 0000000000000..1ac1787fabef5 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys-video.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#ifndef IPU7_ISYS_VIDEO_H +#define IPU7_ISYS_VIDEO_H + +#include <linux/atomic.h> +#include <linux/completion.h> +#include <linux/container_of.h> +#include <linux/list.h> +#include <linux/mutex.h> + +#include <media/media-entity.h> +#include <media/v4l2-dev.h> + +#include "ipu7-isys-queue.h" + +#define IPU_INSYS_OUTPUT_PINS 11U +#define IPU_ISYS_MAX_PARALLEL_SOF 2U + +struct file; +struct ipu7_isys; +struct ipu7_isys_csi2; +struct ipu7_insys_stream_cfg; +struct ipu7_isys_subdev; + +struct ipu7_isys_pixelformat { + u32 pixelformat; + u32 bpp; + u32 bpp_packed; + u32 code; + u32 css_pixelformat; +}; + +struct sequence_info { + unsigned int sequence; + u64 timestamp; +}; + +struct output_pin_data { + void (*pin_ready)(struct ipu7_isys_stream *stream, + struct ipu7_insys_resp *info); + struct ipu7_isys_queue *aq; +}; + +/* + * Align with firmware stream. Each stream represents a CSI virtual channel. + * May map to multiple video devices + */ +struct ipu7_isys_stream { + struct mutex mutex; + struct media_entity *source_entity; + atomic_t sequence; + atomic_t buf_id; + unsigned int seq_index; + struct sequence_info seq[IPU_ISYS_MAX_PARALLEL_SOF]; + int stream_source; + int stream_handle; + unsigned int nr_output_pins; + struct ipu7_isys_subdev *asd; + + int nr_queues; /* Number of capture queues */ + int nr_streaming; + int streaming; + struct list_head queues; + struct completion stream_open_completion; + struct completion stream_close_completion; + struct completion stream_start_completion; + struct completion stream_stop_completion; + struct ipu7_isys *isys; + + struct output_pin_data output_pins[IPU_INSYS_OUTPUT_PINS]; + int error; + u8 vc; +}; + +struct ipu7_isys_video { + struct ipu7_isys_queue aq; + /* Serialise access to other fields in the struct. */ + struct mutex mutex; + struct media_pad pad; + struct video_device vdev; + struct v4l2_pix_format pix_fmt; + struct ipu7_isys *isys; + struct ipu7_isys_csi2 *csi2; + struct ipu7_isys_stream *stream; + unsigned int streaming; + u8 vc; + u8 dt; +}; + +#define ipu7_isys_queue_to_video(__aq) \ + container_of(__aq, struct ipu7_isys_video, aq) + +extern const struct ipu7_isys_pixelformat ipu7_isys_pfmts[]; + +const struct ipu7_isys_pixelformat *ipu7_isys_get_isys_format(u32 pixelformat); +int ipu7_isys_video_prepare_stream(struct ipu7_isys_video *av, + struct media_entity *source_entity, + int nr_queues); +int ipu7_isys_video_set_streaming(struct ipu7_isys_video *av, int state, + struct ipu7_isys_buffer_list *bl); +int ipu7_isys_fw_open(struct ipu7_isys *isys); +void ipu7_isys_fw_close(struct ipu7_isys *isys); +int ipu7_isys_setup_video(struct ipu7_isys_video *av, + struct media_entity **source_entity, int *nr_queues); +int ipu7_isys_video_init(struct ipu7_isys_video *av); +void ipu7_isys_video_cleanup(struct ipu7_isys_video *av); +void ipu7_isys_put_stream(struct ipu7_isys_stream *stream); +struct ipu7_isys_stream * +ipu7_isys_query_stream_by_handle(struct ipu7_isys *isys, + u8 stream_handle); +struct ipu7_isys_stream * +ipu7_isys_query_stream_by_source(struct ipu7_isys *isys, int source, u8 vc); +#endif /* IPU7_ISYS_VIDEO_H */ diff --git a/drivers/staging/media/ipu7/ipu7-isys.c b/drivers/staging/media/ipu7/ipu7-isys.c new file mode 100644 index 0000000000000..cb2f49f3e0fa3 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys.c @@ -0,0 +1,1166 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <linux/auxiliary_bus.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/bug.h> +#include <linux/completion.h> +#include <linux/container_of.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/firmware.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pci.h> +#include <linux/pm_runtime.h> +#include <linux/pm_qos.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/types.h> + +#include <media/ipu-bridge.h> +#include <media/media-entity.h> +#include <media/v4l2-async.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> + +#include "abi/ipu7_fw_isys_abi.h" + +#include "ipu7-bus.h" +#include "ipu7-buttress-regs.h" +#include "ipu7-cpd.h" +#include "ipu7-dma.h" +#include "ipu7-fw-isys.h" +#include "ipu7-mmu.h" +#include "ipu7-isys.h" +#include "ipu7-isys-csi2.h" +#include "ipu7-isys-csi-phy.h" +#include "ipu7-isys-csi2-regs.h" +#include "ipu7-isys-video.h" +#include "ipu7-platform-regs.h" + +#define ISYS_PM_QOS_VALUE 300 + +static int +isys_complete_ext_device_registration(struct ipu7_isys *isys, + struct v4l2_subdev *sd, + struct ipu7_isys_csi2_config *csi2) +{ + struct device *dev = &isys->adev->auxdev.dev; + unsigned int i; + int ret; + + v4l2_set_subdev_hostdata(sd, csi2); + + for (i = 0; i < sd->entity.num_pads; i++) { + if (sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) + break; + } + + if (i == sd->entity.num_pads) { + dev_warn(dev, "no source pad in external entity\n"); + ret = -ENOENT; + goto skip_unregister_subdev; + } + + ret = media_create_pad_link(&sd->entity, i, + &isys->csi2[csi2->port].asd.sd.entity, + 0, MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_warn(dev, "can't create link\n"); + goto skip_unregister_subdev; + } + + isys->csi2[csi2->port].nlanes = csi2->nlanes; + if (csi2->bus_type == V4L2_MBUS_CSI2_DPHY) + isys->csi2[csi2->port].phy_mode = PHY_MODE_DPHY; + else + isys->csi2[csi2->port].phy_mode = PHY_MODE_CPHY; + + return 0; + +skip_unregister_subdev: + v4l2_device_unregister_subdev(sd); + return ret; +} + +static void isys_stream_init(struct ipu7_isys *isys) +{ + unsigned int i; + + for (i = 0; i < IPU_ISYS_MAX_STREAMS; i++) { + mutex_init(&isys->streams[i].mutex); + init_completion(&isys->streams[i].stream_open_completion); + init_completion(&isys->streams[i].stream_close_completion); + init_completion(&isys->streams[i].stream_start_completion); + init_completion(&isys->streams[i].stream_stop_completion); + INIT_LIST_HEAD(&isys->streams[i].queues); + isys->streams[i].isys = isys; + isys->streams[i].stream_handle = i; + isys->streams[i].vc = INVALID_VC_ID; + } +} + +static int isys_fw_log_init(struct ipu7_isys *isys) +{ + struct device *dev = &isys->adev->auxdev.dev; + struct isys_fw_log *fw_log; + void *log_buf; + + if (isys->fw_log) + return 0; + + fw_log = devm_kzalloc(dev, sizeof(*fw_log), GFP_KERNEL); + if (!fw_log) + return -ENOMEM; + + mutex_init(&fw_log->mutex); + + log_buf = devm_kzalloc(dev, FW_LOG_BUF_SIZE, GFP_KERNEL); + if (!log_buf) + return -ENOMEM; + + fw_log->head = log_buf; + fw_log->addr = log_buf; + fw_log->count = 0; + fw_log->size = 0; + + isys->fw_log = fw_log; + + return 0; +} + +/* The .bound() notifier callback when a match is found */ +static int isys_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_connection *asc) +{ + struct ipu7_isys *isys = container_of(notifier, + struct ipu7_isys, notifier); + struct sensor_async_sd *s_asd = + container_of(asc, struct sensor_async_sd, asc); + struct device *dev = &isys->adev->auxdev.dev; + int ret; + + ret = ipu_bridge_instantiate_vcm(sd->dev); + if (ret) { + dev_err(dev, "instantiate vcm failed\n"); + return ret; + } + + dev_info(dev, "bind %s nlanes is %d port is %d\n", + sd->name, s_asd->csi2.nlanes, s_asd->csi2.port); + isys_complete_ext_device_registration(isys, sd, &s_asd->csi2); + + return v4l2_device_register_subdev_nodes(&isys->v4l2_dev); +} + +static int isys_notifier_complete(struct v4l2_async_notifier *notifier) +{ + struct ipu7_isys *isys = container_of(notifier, + struct ipu7_isys, notifier); + + dev_info(&isys->adev->auxdev.dev, + "All sensor registration completed.\n"); + + return v4l2_device_register_subdev_nodes(&isys->v4l2_dev); +} + +static const struct v4l2_async_notifier_operations isys_async_ops = { + .bound = isys_notifier_bound, + .complete = isys_notifier_complete, +}; + +static int isys_notifier_init(struct ipu7_isys *isys) +{ + const struct ipu7_isys_internal_csi2_pdata *csi2 = + &isys->pdata->ipdata->csi2; + struct ipu7_device *isp = isys->adev->isp; + struct device *dev = &isp->pdev->dev; + unsigned int i; + int ret; + + v4l2_async_nf_init(&isys->notifier, &isys->v4l2_dev); + + for (i = 0; i < csi2->nports; i++) { + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_UNKNOWN + }; + struct sensor_async_sd *s_asd; + struct fwnode_handle *ep; + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), i, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!ep) + continue; + + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + if (ret) + goto err_parse; + + if (vep.bus_type != V4L2_MBUS_CSI2_DPHY && + vep.bus_type != V4L2_MBUS_CSI2_CPHY) { + ret = -EINVAL; + dev_err(dev, "unsupported bus type %d!\n", + vep.bus_type); + goto err_parse; + } + + s_asd = v4l2_async_nf_add_fwnode_remote(&isys->notifier, ep, + struct + sensor_async_sd); + if (IS_ERR(s_asd)) { + ret = PTR_ERR(s_asd); + goto err_parse; + } + + s_asd->csi2.port = vep.base.port; + s_asd->csi2.nlanes = vep.bus.mipi_csi2.num_data_lanes; + s_asd->csi2.bus_type = vep.bus_type; + + fwnode_handle_put(ep); + + continue; + +err_parse: + fwnode_handle_put(ep); + return ret; + } + + if (list_empty(&isys->notifier.waiting_list)) { + /* isys probe could continue with async subdevs missing */ + dev_warn(dev, "no subdev found in graph\n"); + return 0; + } + + isys->notifier.ops = &isys_async_ops; + ret = v4l2_async_nf_register(&isys->notifier); + if (ret) { + dev_err(dev, "failed to register async notifier(%d)\n", ret); + v4l2_async_nf_cleanup(&isys->notifier); + } + + return ret; +} + +static void isys_notifier_cleanup(struct ipu7_isys *isys) +{ + v4l2_async_nf_unregister(&isys->notifier); + v4l2_async_nf_cleanup(&isys->notifier); +} + +static void isys_unregister_video_devices(struct ipu7_isys *isys) +{ + const struct ipu7_isys_internal_csi2_pdata *csi2_pdata = + &isys->pdata->ipdata->csi2; + unsigned int i, j; + + for (i = 0; i < csi2_pdata->nports; i++) + for (j = 0; j < IPU7_NR_OF_CSI2_SRC_PADS; j++) + ipu7_isys_video_cleanup(&isys->csi2[i].av[j]); +} + +static int isys_register_video_devices(struct ipu7_isys *isys) +{ + const struct ipu7_isys_internal_csi2_pdata *csi2_pdata = + &isys->pdata->ipdata->csi2; + unsigned int i, j; + int ret; + + for (i = 0; i < csi2_pdata->nports; i++) { + for (j = 0; j < IPU7_NR_OF_CSI2_SRC_PADS; j++) { + struct ipu7_isys_video *av = &isys->csi2[i].av[j]; + + snprintf(av->vdev.name, sizeof(av->vdev.name), + IPU_ISYS_ENTITY_PREFIX " ISYS Capture %u", + i * IPU7_NR_OF_CSI2_SRC_PADS + j); + av->isys = isys; + av->aq.vbq.buf_struct_size = + sizeof(struct ipu7_isys_video_buffer); + + ret = ipu7_isys_video_init(av); + if (ret) + goto fail; + } + } + + return 0; + +fail: + i = i + 1U; + while (i--) { + while (j--) + ipu7_isys_video_cleanup(&isys->csi2[i].av[j]); + j = IPU7_NR_OF_CSI2_SRC_PADS; + } + + return ret; +} + +static void isys_csi2_unregister_subdevices(struct ipu7_isys *isys) +{ + const struct ipu7_isys_internal_csi2_pdata *csi2 = + &isys->pdata->ipdata->csi2; + unsigned int i; + + for (i = 0; i < csi2->nports; i++) + ipu7_isys_csi2_cleanup(&isys->csi2[i]); +} + +static int isys_csi2_register_subdevices(struct ipu7_isys *isys) +{ + const struct ipu7_isys_internal_csi2_pdata *csi2_pdata = + &isys->pdata->ipdata->csi2; + unsigned int i; + int ret; + + for (i = 0; i < csi2_pdata->nports; i++) { + ret = ipu7_isys_csi2_init(&isys->csi2[i], isys, + isys->pdata->base + + csi2_pdata->offsets[i], i); + if (ret) + goto fail; + } + + isys->isr_csi2_mask = IPU7_CSI_RX_LEGACY_IRQ_MASK; + + return 0; + +fail: + while (i--) + ipu7_isys_csi2_cleanup(&isys->csi2[i]); + + return ret; +} + +static int isys_csi2_create_media_links(struct ipu7_isys *isys) +{ + const struct ipu7_isys_internal_csi2_pdata *csi2_pdata = + &isys->pdata->ipdata->csi2; + struct device *dev = &isys->adev->auxdev.dev; + struct media_entity *sd; + unsigned int i, j; + int ret; + + for (i = 0; i < csi2_pdata->nports; i++) { + sd = &isys->csi2[i].asd.sd.entity; + + for (j = 0; j < IPU7_NR_OF_CSI2_SRC_PADS; j++) { + struct ipu7_isys_video *av = &isys->csi2[i].av[j]; + + ret = media_create_pad_link(sd, IPU7_CSI2_PAD_SRC + j, + &av->vdev.entity, 0, 0); + if (ret) { + dev_err(dev, "CSI2 can't create link\n"); + return ret; + } + + av->csi2 = &isys->csi2[i]; + } + } + + return 0; +} + +static int isys_register_devices(struct ipu7_isys *isys) +{ + struct device *dev = &isys->adev->auxdev.dev; + struct pci_dev *pdev = isys->adev->isp->pdev; + int ret; + + media_device_pci_init(&isys->media_dev, + pdev, IPU_MEDIA_DEV_MODEL_NAME); + + strscpy(isys->v4l2_dev.name, isys->media_dev.model, + sizeof(isys->v4l2_dev.name)); + + ret = media_device_register(&isys->media_dev); + if (ret < 0) + goto out_media_device_unregister; + + isys->v4l2_dev.mdev = &isys->media_dev; + isys->v4l2_dev.ctrl_handler = NULL; + + ret = v4l2_device_register(dev, &isys->v4l2_dev); + if (ret < 0) + goto out_media_device_unregister; + + ret = isys_register_video_devices(isys); + if (ret) + goto out_v4l2_device_unregister; + + ret = isys_csi2_register_subdevices(isys); + if (ret) + goto out_video_unregister_device; + + ret = isys_csi2_create_media_links(isys); + if (ret) + goto out_csi2_unregister_subdevices; + + ret = isys_notifier_init(isys); + if (ret) + goto out_csi2_unregister_subdevices; + + return 0; + +out_csi2_unregister_subdevices: + isys_csi2_unregister_subdevices(isys); + +out_video_unregister_device: + isys_unregister_video_devices(isys); + +out_v4l2_device_unregister: + v4l2_device_unregister(&isys->v4l2_dev); + +out_media_device_unregister: + media_device_unregister(&isys->media_dev); + media_device_cleanup(&isys->media_dev); + + dev_err(dev, "failed to register isys devices\n"); + + return ret; +} + +static void isys_unregister_devices(struct ipu7_isys *isys) +{ + isys_unregister_video_devices(isys); + isys_csi2_unregister_subdevices(isys); + v4l2_device_unregister(&isys->v4l2_dev); + media_device_unregister(&isys->media_dev); + media_device_cleanup(&isys->media_dev); +} + +static void enable_csi2_legacy_irq(struct ipu7_isys *isys, bool enable) +{ + u32 offset = IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE; + void __iomem *base = isys->pdata->base; + u32 mask = isys->isr_csi2_mask; + + if (!enable) { + writel(mask, base + offset + IRQ_CTL_CLEAR); + writel(0, base + offset + IRQ_CTL_ENABLE); + return; + } + + writel(mask, base + offset + IRQ_CTL_EDGE); + writel(mask, base + offset + IRQ_CTL_CLEAR); + writel(mask, base + offset + IRQ_CTL_MASK); + writel(mask, base + offset + IRQ_CTL_ENABLE); +} + +static void enable_to_sw_irq(struct ipu7_isys *isys, bool enable) +{ + void __iomem *base = isys->pdata->base; + u32 mask = IS_UC_TO_SW_IRQ_MASK; + u32 offset = IS_UC_CTRL_BASE; + + if (!enable) { + writel(0, base + offset + TO_SW_IRQ_CNTL_ENABLE); + return; + } + + writel(mask, base + offset + TO_SW_IRQ_CNTL_CLEAR); + writel(mask, base + offset + TO_SW_IRQ_CNTL_MASK_N); + writel(mask, base + offset + TO_SW_IRQ_CNTL_ENABLE); +} + +void ipu7_isys_setup_hw(struct ipu7_isys *isys) +{ + u32 offset; + void __iomem *base = isys->pdata->base; + + /* soft reset */ + offset = IS_IO_GPREGS_BASE; + + writel(0x0, base + offset + CLK_EN_TXCLKESC); + /* Update if ISYS freq updated (0: 400/1, 1:400/2, 63:400/64) */ + writel(0x0, base + offset + CLK_DIV_FACTOR_IS_CLK); + /* correct the initial printf configuration */ + writel(0x200, base + IS_UC_CTRL_BASE + PRINTF_AXI_CNTL); + + enable_to_sw_irq(isys, 1); + enable_csi2_legacy_irq(isys, 1); +} + +static void isys_cleanup_hw(struct ipu7_isys *isys) +{ + enable_csi2_legacy_irq(isys, 0); + enable_to_sw_irq(isys, 0); +} + +static int isys_runtime_pm_resume(struct device *dev) +{ + struct ipu7_bus_device *adev = to_ipu7_bus_device(dev); + struct ipu7_isys *isys = ipu7_bus_get_drvdata(adev); + struct ipu7_device *isp = adev->isp; + unsigned long flags; + int ret; + + if (!isys) + return 0; + + ret = ipu7_mmu_hw_init(adev->mmu); + if (ret) + return ret; + + cpu_latency_qos_update_request(&isys->pm_qos, ISYS_PM_QOS_VALUE); + + ret = ipu_buttress_start_tsc_sync(isp); + if (ret) + return ret; + + spin_lock_irqsave(&isys->power_lock, flags); + isys->power = 1; + spin_unlock_irqrestore(&isys->power_lock, flags); + + return 0; +} + +static int isys_runtime_pm_suspend(struct device *dev) +{ + struct ipu7_bus_device *adev = to_ipu7_bus_device(dev); + struct ipu7_isys *isys = ipu7_bus_get_drvdata(adev); + unsigned long flags; + + if (!isys) + return 0; + + isys_cleanup_hw(isys); + + spin_lock_irqsave(&isys->power_lock, flags); + isys->power = 0; + spin_unlock_irqrestore(&isys->power_lock, flags); + + cpu_latency_qos_update_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE); + + ipu7_mmu_hw_cleanup(adev->mmu); + + return 0; +} + +static int isys_suspend(struct device *dev) +{ + struct ipu7_isys *isys = dev_get_drvdata(dev); + + /* If stream is open, refuse to suspend */ + if (isys->stream_opened) + return -EBUSY; + + return 0; +} + +static int isys_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops isys_pm_ops = { + .runtime_suspend = isys_runtime_pm_suspend, + .runtime_resume = isys_runtime_pm_resume, + .suspend = isys_suspend, + .resume = isys_resume, +}; + +static void isys_remove(struct auxiliary_device *auxdev) +{ + struct ipu7_isys *isys = dev_get_drvdata(&auxdev->dev); + struct isys_fw_msgs *fwmsg, *safe; + struct ipu7_bus_device *adev = auxdev_to_adev(auxdev); + + for (int i = 0; i < IPU_ISYS_MAX_STREAMS; i++) + mutex_destroy(&isys->streams[i].mutex); + + list_for_each_entry_safe(fwmsg, safe, &isys->framebuflist, head) + ipu7_dma_free(adev, sizeof(struct isys_fw_msgs), + fwmsg, fwmsg->dma_addr, 0); + + list_for_each_entry_safe(fwmsg, safe, &isys->framebuflist_fw, head) + ipu7_dma_free(adev, sizeof(struct isys_fw_msgs), + fwmsg, fwmsg->dma_addr, 0); + + isys_notifier_cleanup(isys); + isys_unregister_devices(isys); + + cpu_latency_qos_remove_request(&isys->pm_qos); + + mutex_destroy(&isys->stream_mutex); + mutex_destroy(&isys->mutex); +} + +static int alloc_fw_msg_bufs(struct ipu7_isys *isys, int amount) +{ + struct ipu7_bus_device *adev = isys->adev; + struct isys_fw_msgs *addr; + dma_addr_t dma_addr; + unsigned long flags; + unsigned int i; + + for (i = 0; i < amount; i++) { + addr = ipu7_dma_alloc(adev, sizeof(struct isys_fw_msgs), + &dma_addr, GFP_KERNEL, 0); + if (!addr) + break; + addr->dma_addr = dma_addr; + + spin_lock_irqsave(&isys->listlock, flags); + list_add(&addr->head, &isys->framebuflist); + spin_unlock_irqrestore(&isys->listlock, flags); + } + + if (i == amount) + return 0; + + spin_lock_irqsave(&isys->listlock, flags); + while (!list_empty(&isys->framebuflist)) { + addr = list_first_entry(&isys->framebuflist, + struct isys_fw_msgs, head); + list_del(&addr->head); + spin_unlock_irqrestore(&isys->listlock, flags); + ipu7_dma_free(adev, sizeof(struct isys_fw_msgs), + addr, addr->dma_addr, 0); + spin_lock_irqsave(&isys->listlock, flags); + } + spin_unlock_irqrestore(&isys->listlock, flags); + + return -ENOMEM; +} + +struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream) +{ + struct device *dev = &stream->isys->adev->auxdev.dev; + struct ipu7_isys *isys = stream->isys; + struct isys_fw_msgs *msg; + unsigned long flags; + int ret; + + spin_lock_irqsave(&isys->listlock, flags); + if (list_empty(&isys->framebuflist)) { + spin_unlock_irqrestore(&isys->listlock, flags); + dev_dbg(dev, "Frame buffer list empty\n"); + + ret = alloc_fw_msg_bufs(isys, 5); + if (ret < 0) + return NULL; + + spin_lock_irqsave(&isys->listlock, flags); + if (list_empty(&isys->framebuflist)) { + spin_unlock_irqrestore(&isys->listlock, flags); + dev_err(dev, "Frame list empty\n"); + return NULL; + } + } + msg = list_last_entry(&isys->framebuflist, struct isys_fw_msgs, head); + list_move(&msg->head, &isys->framebuflist_fw); + spin_unlock_irqrestore(&isys->listlock, flags); + memset(&msg->fw_msg, 0, sizeof(msg->fw_msg)); + + return msg; +} + +void ipu7_cleanup_fw_msg_bufs(struct ipu7_isys *isys) +{ + struct isys_fw_msgs *fwmsg, *fwmsg0; + unsigned long flags; + + spin_lock_irqsave(&isys->listlock, flags); + list_for_each_entry_safe(fwmsg, fwmsg0, &isys->framebuflist_fw, head) + list_move(&fwmsg->head, &isys->framebuflist); + spin_unlock_irqrestore(&isys->listlock, flags); +} + +void ipu7_put_fw_msg_buf(struct ipu7_isys *isys, uintptr_t data) +{ + struct isys_fw_msgs *msg; + void *ptr = (void *)data; + unsigned long flags; + + if (WARN_ON_ONCE(!ptr)) + return; + + spin_lock_irqsave(&isys->listlock, flags); + msg = container_of(ptr, struct isys_fw_msgs, fw_msg.dummy); + list_move(&msg->head, &isys->framebuflist); + spin_unlock_irqrestore(&isys->listlock, flags); +} + +static int isys_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *auxdev_id) +{ + const struct ipu7_isys_internal_csi2_pdata *csi2_pdata; + struct ipu7_bus_device *adev = auxdev_to_adev(auxdev); + struct ipu7_device *isp = adev->isp; + struct ipu7_isys *isys; + int ret = 0; + + if (!isp->ipu7_bus_ready_to_probe) + return -EPROBE_DEFER; + + isys = devm_kzalloc(&auxdev->dev, sizeof(*isys), GFP_KERNEL); + if (!isys) + return -ENOMEM; + + ret = pm_runtime_resume_and_get(&auxdev->dev); + if (ret < 0) + return ret; + + adev->auxdrv_data = + (const struct ipu7_auxdrv_data *)auxdev_id->driver_data; + adev->auxdrv = to_auxiliary_drv(auxdev->dev.driver); + isys->adev = adev; + isys->pdata = adev->pdata; + + INIT_LIST_HEAD(&isys->requests); + csi2_pdata = &isys->pdata->ipdata->csi2; + + isys->csi2 = devm_kcalloc(&auxdev->dev, csi2_pdata->nports, + sizeof(*isys->csi2), GFP_KERNEL); + if (!isys->csi2) { + ret = -ENOMEM; + goto out_runtime_put; + } + + ret = ipu7_mmu_hw_init(adev->mmu); + if (ret) + goto out_runtime_put; + + spin_lock_init(&isys->streams_lock); + spin_lock_init(&isys->power_lock); + isys->power = 0; + + mutex_init(&isys->mutex); + mutex_init(&isys->stream_mutex); + + spin_lock_init(&isys->listlock); + INIT_LIST_HEAD(&isys->framebuflist); + INIT_LIST_HEAD(&isys->framebuflist_fw); + + dev_set_drvdata(&auxdev->dev, isys); + + isys->icache_prefetch = 0; + isys->phy_rext_cal = 0; + + isys_stream_init(isys); + + cpu_latency_qos_add_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE); + ret = alloc_fw_msg_bufs(isys, 20); + if (ret < 0) + goto out_cleanup_isys; + + ret = ipu7_fw_isys_init(isys); + if (ret) + goto out_cleanup_isys; + + ret = isys_register_devices(isys); + if (ret) + goto out_cleanup_fw; + + ret = isys_fw_log_init(isys); + if (ret) + goto out_cleanup; + + ipu7_mmu_hw_cleanup(adev->mmu); + pm_runtime_put(&auxdev->dev); + + return 0; + +out_cleanup: + isys_unregister_devices(isys); +out_cleanup_fw: + ipu7_fw_isys_release(isys); +out_cleanup_isys: + cpu_latency_qos_remove_request(&isys->pm_qos); + + for (unsigned int i = 0; i < IPU_ISYS_MAX_STREAMS; i++) + mutex_destroy(&isys->streams[i].mutex); + + mutex_destroy(&isys->mutex); + mutex_destroy(&isys->stream_mutex); + + ipu7_mmu_hw_cleanup(adev->mmu); + +out_runtime_put: + pm_runtime_put(&auxdev->dev); + + return ret; +} + +struct ipu7_csi2_error { + const char *error_string; + bool is_info_only; +}; + +/* + * Strings corresponding to CSI-2 receiver errors are here. + * Corresponding macros are defined in the header file. + */ +static const struct ipu7_csi2_error dphy_rx_errors[] = { + { "Error handler FIFO full", false }, + { "Reserved Short Packet encoding detected", true }, + { "Reserved Long Packet encoding detected", true }, + { "Received packet is too short", false}, + { "Received packet is too long", false}, + { "Short packet discarded due to errors", false }, + { "Long packet discarded due to errors", false }, + { "CSI Combo Rx interrupt", false }, + { "IDI CDC FIFO overflow(remaining bits are reserved as 0)", false }, + { "Received NULL packet", true }, + { "Received blanking packet", true }, + { "Tie to 0", true }, + { } +}; + +static void ipu7_isys_register_errors(struct ipu7_isys_csi2 *csi2) +{ + u32 offset = IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port); + u32 status = readl(csi2->base + offset + IRQ_CTL_STATUS); + u32 mask = IPU7_CSI_RX_ERROR_IRQ_MASK; + + if (!status) + return; + + dev_dbg(&csi2->isys->adev->auxdev.dev, "csi2-%u error status 0x%08x\n", + csi2->port, status); + + writel(status & mask, csi2->base + offset + IRQ_CTL_CLEAR); + csi2->receiver_errors |= status & mask; +} + +static void ipu7_isys_csi2_error(struct ipu7_isys_csi2 *csi2) +{ + struct ipu7_csi2_error const *errors; + unsigned int i; + u32 status; + + /* Register errors once more in case of error interrupts are disabled */ + ipu7_isys_register_errors(csi2); + status = csi2->receiver_errors; + csi2->receiver_errors = 0; + errors = dphy_rx_errors; + + for (i = 0; i < CSI_RX_NUM_ERRORS_IN_IRQ; i++) { + if (status & BIT(i)) + dev_err_ratelimited(&csi2->isys->adev->auxdev.dev, + "csi2-%i error: %s\n", + csi2->port, + errors[i].error_string); + } +} + +struct resp_to_msg { + enum ipu7_insys_resp_type type; + const char *msg; +}; + +static const struct resp_to_msg is_fw_msg[] = { + {IPU_INSYS_RESP_TYPE_STREAM_OPEN_DONE, + "IPU_INSYS_RESP_TYPE_STREAM_OPEN_DONE"}, + {IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK, + "IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK"}, + {IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK, + "IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK"}, + {IPU_INSYS_RESP_TYPE_STREAM_ABORT_ACK, + "IPU_INSYS_RESP_TYPE_STREAM_ABORT_ACK"}, + {IPU_INSYS_RESP_TYPE_STREAM_FLUSH_ACK, + "IPU_INSYS_RESP_TYPE_STREAM_FLUSH_ACK"}, + {IPU_INSYS_RESP_TYPE_STREAM_CLOSE_ACK, + "IPU_INSYS_RESP_TYPE_STREAM_CLOSE_ACK"}, + {IPU_INSYS_RESP_TYPE_PIN_DATA_READY, + "IPU_INSYS_RESP_TYPE_PIN_DATA_READY"}, + {IPU_INSYS_RESP_TYPE_FRAME_SOF, "IPU_INSYS_RESP_TYPE_FRAME_SOF"}, + {IPU_INSYS_RESP_TYPE_FRAME_EOF, "IPU_INSYS_RESP_TYPE_FRAME_EOF"}, + {IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE, + "IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE"}, + {IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE, + "IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE"}, + {N_IPU_INSYS_RESP_TYPE, "N_IPU_INSYS_RESP_TYPE"}, +}; + +int isys_isr_one(struct ipu7_bus_device *adev) +{ + struct ipu7_isys *isys = ipu7_bus_get_drvdata(adev); + struct ipu7_isys_stream *stream = NULL; + struct device *dev = &adev->auxdev.dev; + struct ipu7_isys_csi2 *csi2 = NULL; + struct ia_gofo_msg_err err_info; + struct ipu7_insys_resp *resp; + u64 ts; + + if (!isys->adev->syscom) + return 1; + + resp = ipu7_fw_isys_get_resp(isys); + if (!resp) + return 1; + if (resp->type >= N_IPU_INSYS_RESP_TYPE) { + dev_err(dev, "Unknown response type %u stream %u\n", + resp->type, resp->stream_id); + ipu7_fw_isys_put_resp(isys); + return 1; + } + + err_info = resp->error_info; + ts = ((u64)resp->timestamp[1] << 32) | resp->timestamp[0]; + if (err_info.err_group == INSYS_MSG_ERR_GROUP_CAPTURE && + err_info.err_code == INSYS_MSG_ERR_CAPTURE_SYNC_FRAME_DROP) { + /* receive a sp w/o command, firmware drop it */ + dev_dbg(dev, "FRAME DROP: %02u %s stream %u\n", + resp->type, is_fw_msg[resp->type].msg, + resp->stream_id); + dev_dbg(dev, "\tpin %u buf_id %llx frame %u\n", + resp->pin_id, resp->buf_id, resp->frame_id); + dev_dbg(dev, "\terror group %u code %u details [%u %u]\n", + err_info.err_group, err_info.err_code, + err_info.err_detail[0], err_info.err_detail[1]); + } else if (!IA_GOFO_MSG_ERR_IS_OK(err_info)) { + dev_err(dev, "%02u %s stream %u pin %u buf_id %llx frame %u\n", + resp->type, is_fw_msg[resp->type].msg, resp->stream_id, + resp->pin_id, resp->buf_id, resp->frame_id); + dev_err(dev, "\terror group %u code %u details [%u %u]\n", + err_info.err_group, err_info.err_code, + err_info.err_detail[0], err_info.err_detail[1]); + } else { + dev_dbg(dev, "%02u %s stream %u pin %u buf_id %llx frame %u\n", + resp->type, is_fw_msg[resp->type].msg, resp->stream_id, + resp->pin_id, resp->buf_id, resp->frame_id); + dev_dbg(dev, "\tts %llu\n", ts); + } + + if (resp->stream_id >= IPU_ISYS_MAX_STREAMS) { + dev_err(dev, "bad stream handle %u\n", + resp->stream_id); + goto leave; + } + + stream = ipu7_isys_query_stream_by_handle(isys, resp->stream_id); + if (!stream) { + dev_err(dev, "stream of stream_handle %u is unused\n", + resp->stream_id); + goto leave; + } + + stream->error = err_info.err_code; + + if (stream->asd) + csi2 = ipu7_isys_subdev_to_csi2(stream->asd); + + switch (resp->type) { + case IPU_INSYS_RESP_TYPE_STREAM_OPEN_DONE: + complete(&stream->stream_open_completion); + break; + case IPU_INSYS_RESP_TYPE_STREAM_CLOSE_ACK: + complete(&stream->stream_close_completion); + break; + case IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK: + complete(&stream->stream_start_completion); + break; + case IPU_INSYS_RESP_TYPE_STREAM_ABORT_ACK: + complete(&stream->stream_stop_completion); + break; + case IPU_INSYS_RESP_TYPE_STREAM_FLUSH_ACK: + complete(&stream->stream_stop_completion); + break; + case IPU_INSYS_RESP_TYPE_PIN_DATA_READY: + /* + * firmware only release the capture msg until software + * get pin_data_ready event + */ + ipu7_put_fw_msg_buf(ipu7_bus_get_drvdata(adev), resp->buf_id); + if (resp->pin_id < IPU_INSYS_OUTPUT_PINS && + stream->output_pins[resp->pin_id].pin_ready) + stream->output_pins[resp->pin_id].pin_ready(stream, + resp); + else + dev_err(dev, "No handler for pin %u ready\n", + resp->pin_id); + if (csi2) + ipu7_isys_csi2_error(csi2); + + break; + case IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK: + break; + case IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE: + case IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE: + break; + case IPU_INSYS_RESP_TYPE_FRAME_SOF: + if (csi2) + ipu7_isys_csi2_sof_event_by_stream(stream); + + stream->seq[stream->seq_index].sequence = + atomic_read(&stream->sequence) - 1U; + stream->seq[stream->seq_index].timestamp = ts; + dev_dbg(dev, + "SOF: stream %u frame %u (index %u), ts 0x%16.16llx\n", + resp->stream_id, resp->frame_id, + stream->seq[stream->seq_index].sequence, ts); + stream->seq_index = (stream->seq_index + 1U) + % IPU_ISYS_MAX_PARALLEL_SOF; + break; + case IPU_INSYS_RESP_TYPE_FRAME_EOF: + if (csi2) + ipu7_isys_csi2_eof_event_by_stream(stream); + + dev_dbg(dev, "eof: stream %d(index %u) ts 0x%16.16llx\n", + resp->stream_id, + stream->seq[stream->seq_index].sequence, ts); + break; + default: + dev_err(dev, "Unknown response type %u stream %u\n", + resp->type, resp->stream_id); + break; + } + + ipu7_isys_put_stream(stream); +leave: + ipu7_fw_isys_put_resp(isys); + + return 0; +} + +static void ipu7_isys_csi2_isr(struct ipu7_isys_csi2 *csi2) +{ + struct device *dev = &csi2->isys->adev->auxdev.dev; + struct ipu7_device *isp = csi2->isys->adev->isp; + struct ipu7_isys_stream *s; + u32 sync, offset; + u32 fe = 0; + u8 vc; + + ipu7_isys_register_errors(csi2); + + offset = IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port); + sync = readl(csi2->base + offset + IRQ_CTL_STATUS); + writel(sync, csi2->base + offset + IRQ_CTL_CLEAR); + dev_dbg(dev, "csi2-%u sync status 0x%08x\n", csi2->port, sync); + + if (!is_ipu7(isp->hw_ver)) { + fe = readl(csi2->base + offset + IRQ1_CTL_STATUS); + writel(fe, csi2->base + offset + IRQ1_CTL_CLEAR); + dev_dbg(dev, "csi2-%u FE status 0x%08x\n", csi2->port, fe); + } + + for (vc = 0; vc < IPU7_NR_OF_CSI2_VC && (sync || fe); vc++) { + s = ipu7_isys_query_stream_by_source(csi2->isys, + csi2->asd.source, vc); + if (!s) + continue; + + if (!is_ipu7(isp->hw_ver)) { + if (sync & IPU7P5_CSI_RX_SYNC_FS_VC & (1U << vc)) + ipu7_isys_csi2_sof_event_by_stream(s); + + if (fe & IPU7P5_CSI_RX_SYNC_FE_VC & (1U << vc)) + ipu7_isys_csi2_eof_event_by_stream(s); + } else { + if (sync & IPU7_CSI_RX_SYNC_FS_VC & (1U << (vc * 2))) + ipu7_isys_csi2_sof_event_by_stream(s); + + if (sync & IPU7_CSI_RX_SYNC_FE_VC & (2U << (vc * 2))) + ipu7_isys_csi2_eof_event_by_stream(s); + } + } +} + +static irqreturn_t isys_isr(struct ipu7_bus_device *adev) +{ + struct ipu7_isys *isys = ipu7_bus_get_drvdata(adev); + u32 status_csi, status_sw, csi_offset, sw_offset; + struct device *dev = &isys->adev->auxdev.dev; + void __iomem *base = isys->pdata->base; + + spin_lock(&isys->power_lock); + if (!isys->power) { + spin_unlock(&isys->power_lock); + return IRQ_NONE; + } + + csi_offset = IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE; + sw_offset = IS_BASE; + + status_csi = readl(base + csi_offset + IRQ_CTL_STATUS); + status_sw = readl(base + sw_offset + TO_SW_IRQ_CNTL_STATUS); + if (!status_csi && !status_sw) { + spin_unlock(&isys->power_lock); + return IRQ_NONE; + } + + if (status_csi) + dev_dbg(dev, "status csi 0x%08x\n", status_csi); + if (status_sw) + dev_dbg(dev, "status to_sw 0x%08x\n", status_sw); + + do { + writel(status_sw, base + sw_offset + TO_SW_IRQ_CNTL_CLEAR); + writel(status_csi, base + csi_offset + IRQ_CTL_CLEAR); + + if (isys->isr_csi2_mask & status_csi) { + unsigned int i; + + for (i = 0; i < isys->pdata->ipdata->csi2.nports; i++) { + /* irq from not enabled port */ + if (!isys->csi2[i].base) + continue; + if (status_csi & isys->csi2[i].legacy_irq_mask) + ipu7_isys_csi2_isr(&isys->csi2[i]); + } + } + + if (!isys_isr_one(adev)) + status_sw = TO_SW_IRQ_FW; + else + status_sw = 0; + + status_csi = readl(base + csi_offset + IRQ_CTL_STATUS); + status_sw |= readl(base + sw_offset + TO_SW_IRQ_CNTL_STATUS); + } while ((status_csi & isys->isr_csi2_mask) || + (status_sw & TO_SW_IRQ_FW)); + + writel(TO_SW_IRQ_MASK, base + sw_offset + TO_SW_IRQ_CNTL_MASK_N); + + spin_unlock(&isys->power_lock); + + return IRQ_HANDLED; +} + +static const struct ipu7_auxdrv_data ipu7_isys_auxdrv_data = { + .isr = isys_isr, + .isr_threaded = NULL, + .wake_isr_thread = false, +}; + +static const struct auxiliary_device_id ipu7_isys_id_table[] = { + { + .name = "intel_ipu7.isys", + .driver_data = (kernel_ulong_t)&ipu7_isys_auxdrv_data, + }, + { } +}; +MODULE_DEVICE_TABLE(auxiliary, ipu7_isys_id_table); + +static struct auxiliary_driver isys_driver = { + .name = IPU_ISYS_NAME, + .probe = isys_probe, + .remove = isys_remove, + .id_table = ipu7_isys_id_table, + .driver = { + .pm = &isys_pm_ops, + }, +}; + +module_auxiliary_driver(isys_driver); + +MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>"); +MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>"); +MODULE_AUTHOR("Qingwu Zhang <qingwu.zhang@intel.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Intel ipu7 input system driver"); +MODULE_IMPORT_NS("INTEL_IPU7"); +MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); diff --git a/drivers/staging/media/ipu7/ipu7-isys.h b/drivers/staging/media/ipu7/ipu7-isys.h new file mode 100644 index 0000000000000..ef1ab1b42f6c2 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-isys.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#ifndef IPU7_ISYS_H +#define IPU7_ISYS_H + +#include <linux/irqreturn.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/pm_qos.h> +#include <linux/spinlock_types.h> +#include <linux/types.h> + +#include <media/media-device.h> +#include <media/v4l2-async.h> +#include <media/v4l2-device.h> +#include <media/v4l2-mediabus.h> + +#include "abi/ipu7_fw_msg_abi.h" +#include "abi/ipu7_fw_isys_abi.h" + +#include "ipu7.h" +#include "ipu7-isys-csi2.h" +#include "ipu7-isys-video.h" + +#define IPU_ISYS_ENTITY_PREFIX "Intel IPU7" + +/* FW support max 16 streams */ +#define IPU_ISYS_MAX_STREAMS 16U + +/* + * Current message queue configuration. These must be big enough + * so that they never gets full. Queues are located in system memory + */ +#define IPU_ISYS_SIZE_RECV_QUEUE 40U +#define IPU_ISYS_SIZE_LOG_QUEUE 256U +#define IPU_ISYS_SIZE_SEND_QUEUE 40U +#define IPU_ISYS_NUM_RECV_QUEUE 1U + +#define IPU_ISYS_MIN_WIDTH 2U +#define IPU_ISYS_MIN_HEIGHT 2U +#define IPU_ISYS_MAX_WIDTH 8160U +#define IPU_ISYS_MAX_HEIGHT 8190U + +#define FW_CALL_TIMEOUT_JIFFIES \ + msecs_to_jiffies(IPU_LIB_CALL_TIMEOUT_MS) + +struct isys_fw_log { + struct mutex mutex; /* protect whole struct */ + void *head; + void *addr; + u32 count; /* running counter of log */ + u32 size; /* actual size of log content, in bits */ +}; + +/* + * struct ipu7_isys + * + * @media_dev: Media device + * @v4l2_dev: V4L2 device + * @adev: ISYS bus device + * @power: Is ISYS powered on or not? + * @isr_bits: Which bits does the ISR handle? + * @power_lock: Serialise access to power (power state in general) + * @csi2_rx_ctrl_cached: cached shared value between all CSI2 receivers + * @streams_lock: serialise access to streams + * @streams: streams per firmware stream ID + * @syscom: fw communication layer context + * @ref_count: total number of callers fw open + * @mutex: serialise access isys video open/release related operations + * @stream_mutex: serialise stream start and stop, queueing requests + * @pdata: platform data pointer + * @csi2: CSI-2 receivers + */ +struct ipu7_isys { + struct media_device media_dev; + struct v4l2_device v4l2_dev; + struct ipu7_bus_device *adev; + + int power; + spinlock_t power_lock; /* Serialise access to power */ + u32 isr_csi2_mask; + u32 csi2_rx_ctrl_cached; + spinlock_t streams_lock; + struct ipu7_isys_stream streams[IPU_ISYS_MAX_STREAMS]; + int streams_ref_count[IPU_ISYS_MAX_STREAMS]; + u32 phy_rext_cal; + bool icache_prefetch; + bool csi2_cse_ipc_not_supported; + unsigned int ref_count; + unsigned int stream_opened; + + struct mutex mutex; /* Serialise isys video open/release related */ + struct mutex stream_mutex; /* Stream start, stop, queueing reqs */ + + struct ipu7_isys_pdata *pdata; + + struct ipu7_isys_csi2 *csi2; + struct isys_fw_log *fw_log; + + struct list_head requests; + struct pm_qos_request pm_qos; + spinlock_t listlock; /* Protect framebuflist */ + struct list_head framebuflist; + struct list_head framebuflist_fw; + struct v4l2_async_notifier notifier; + + struct ipu7_insys_config *subsys_config; + dma_addr_t subsys_config_dma_addr; +}; + +struct isys_fw_msgs { + union { + u64 dummy; + struct ipu7_insys_buffset frame; + struct ipu7_insys_stream_cfg stream; + } fw_msg; + struct list_head head; + dma_addr_t dma_addr; +}; + +struct ipu7_isys_csi2_config { + unsigned int nlanes; + unsigned int port; + enum v4l2_mbus_type bus_type; +}; + +struct sensor_async_sd { + struct v4l2_async_connection asc; + struct ipu7_isys_csi2_config csi2; +}; + +struct isys_fw_msgs *ipu7_get_fw_msg_buf(struct ipu7_isys_stream *stream); +void ipu7_put_fw_msg_buf(struct ipu7_isys *isys, uintptr_t data); +void ipu7_cleanup_fw_msg_bufs(struct ipu7_isys *isys); +int isys_isr_one(struct ipu7_bus_device *adev); +void ipu7_isys_setup_hw(struct ipu7_isys *isys); +#endif /* IPU7_ISYS_H */ diff --git a/drivers/staging/media/ipu7/ipu7-mmu.c b/drivers/staging/media/ipu7/ipu7-mmu.c new file mode 100644 index 0000000000000..ded1986eb8ba3 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-mmu.c @@ -0,0 +1,853 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <asm/barrier.h> + +#include <linux/align.h> +#include <linux/atomic.h> +#include <linux/bitops.h> +#include <linux/bits.h> +#include <linux/bug.h> +#include <linux/cacheflush.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/gfp.h> +#include <linux/iopoll.h> +#include <linux/iova.h> +#include <linux/math.h> +#include <linux/minmax.h> +#include <linux/pci.h> +#include <linux/pfn.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/vmalloc.h> + +#include "ipu7.h" +#include "ipu7-dma.h" +#include "ipu7-mmu.h" +#include "ipu7-platform-regs.h" + +#define ISP_PAGE_SHIFT 12 +#define ISP_PAGE_SIZE BIT(ISP_PAGE_SHIFT) +#define ISP_PAGE_MASK (~(ISP_PAGE_SIZE - 1U)) + +#define ISP_L1PT_SHIFT 22 +#define ISP_L1PT_MASK (~((1U << ISP_L1PT_SHIFT) - 1)) + +#define ISP_L2PT_SHIFT 12 +#define ISP_L2PT_MASK (~(ISP_L1PT_MASK | (~(ISP_PAGE_MASK)))) + +#define ISP_L1PT_PTES 1024U +#define ISP_L2PT_PTES 1024U + +#define ISP_PADDR_SHIFT 12 + +#define REG_L1_PHYS 0x0004 /* 27-bit pfn */ +#define REG_INFO 0x0008 + +#define TBL_PHYS_ADDR(a) ((phys_addr_t)(a) << ISP_PADDR_SHIFT) + +#define MMU_TLB_INVALIDATE_TIMEOUT 2000 + +static __maybe_unused void mmu_irq_handler(struct ipu7_mmu *mmu) +{ + unsigned int i; + u32 irq_cause; + + for (i = 0; i < mmu->nr_mmus; i++) { + irq_cause = readl(mmu->mmu_hw[i].base + MMU_REG_IRQ_CAUSE); + pr_info("mmu %s irq_cause = 0x%x", mmu->mmu_hw[i].name, + irq_cause); + writel(0x1ffff, mmu->mmu_hw[i].base + MMU_REG_IRQ_CLEAR); + } +} + +static void tlb_invalidate(struct ipu7_mmu *mmu) +{ + unsigned long flags; + unsigned int i; + int ret; + u32 val; + + spin_lock_irqsave(&mmu->ready_lock, flags); + if (!mmu->ready) { + spin_unlock_irqrestore(&mmu->ready_lock, flags); + return; + } + + for (i = 0; i < mmu->nr_mmus; i++) { + writel(0xffffffffU, mmu->mmu_hw[i].base + + MMU_REG_INVALIDATE_0); + + /* Need check with HW, use l1streams or l2streams */ + if (mmu->mmu_hw[i].nr_l2streams > 32) + writel(0xffffffffU, mmu->mmu_hw[i].base + + MMU_REG_INVALIDATE_1); + + /* + * The TLB invalidation is a "single cycle" (IOMMU clock cycles) + * When the actual MMIO write reaches the IPU TLB Invalidate + * register, wmb() will force the TLB invalidate out if the CPU + * attempts to update the IOMMU page table (or sooner). + */ + wmb(); + + /* wait invalidation done */ + ret = readl_poll_timeout_atomic(mmu->mmu_hw[i].base + + MMU_REG_INVALIDATION_STATUS, + val, !(val & 0x1U), 500, + MMU_TLB_INVALIDATE_TIMEOUT); + if (ret) + dev_err(mmu->dev, "MMU[%u] TLB invalidate failed\n", i); + } + + spin_unlock_irqrestore(&mmu->ready_lock, flags); +} + +static dma_addr_t map_single(struct ipu7_mmu_info *mmu_info, void *ptr) +{ + dma_addr_t dma; + + dma = dma_map_single(mmu_info->dev, ptr, PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(mmu_info->dev, dma)) + return 0; + + return dma; +} + +static int get_dummy_page(struct ipu7_mmu_info *mmu_info) +{ + void *pt = (void *)get_zeroed_page(GFP_ATOMIC | GFP_DMA32); + dma_addr_t dma; + + if (!pt) + return -ENOMEM; + + dev_dbg(mmu_info->dev, "dummy_page: get_zeroed_page() == %p\n", pt); + + dma = map_single(mmu_info, pt); + if (!dma) { + dev_err(mmu_info->dev, "Failed to map dummy page\n"); + goto err_free_page; + } + + mmu_info->dummy_page = pt; + mmu_info->dummy_page_pteval = dma >> ISP_PAGE_SHIFT; + + return 0; + +err_free_page: + free_page((unsigned long)pt); + return -ENOMEM; +} + +static void free_dummy_page(struct ipu7_mmu_info *mmu_info) +{ + dma_unmap_single(mmu_info->dev, + TBL_PHYS_ADDR(mmu_info->dummy_page_pteval), + PAGE_SIZE, DMA_BIDIRECTIONAL); + free_page((unsigned long)mmu_info->dummy_page); +} + +static int alloc_dummy_l2_pt(struct ipu7_mmu_info *mmu_info) +{ + u32 *pt = (u32 *)get_zeroed_page(GFP_ATOMIC | GFP_DMA32); + dma_addr_t dma; + unsigned int i; + + if (!pt) + return -ENOMEM; + + dev_dbg(mmu_info->dev, "dummy_l2: get_zeroed_page() = %p\n", pt); + + dma = map_single(mmu_info, pt); + if (!dma) { + dev_err(mmu_info->dev, "Failed to map l2pt page\n"); + goto err_free_page; + } + + for (i = 0; i < ISP_L2PT_PTES; i++) + pt[i] = mmu_info->dummy_page_pteval; + + mmu_info->dummy_l2_pt = pt; + mmu_info->dummy_l2_pteval = dma >> ISP_PAGE_SHIFT; + + return 0; + +err_free_page: + free_page((unsigned long)pt); + return -ENOMEM; +} + +static void free_dummy_l2_pt(struct ipu7_mmu_info *mmu_info) +{ + dma_unmap_single(mmu_info->dev, + TBL_PHYS_ADDR(mmu_info->dummy_l2_pteval), + PAGE_SIZE, DMA_BIDIRECTIONAL); + free_page((unsigned long)mmu_info->dummy_l2_pt); +} + +static u32 *alloc_l1_pt(struct ipu7_mmu_info *mmu_info) +{ + u32 *pt = (u32 *)get_zeroed_page(GFP_ATOMIC | GFP_DMA32); + dma_addr_t dma; + unsigned int i; + + if (!pt) + return NULL; + + dev_dbg(mmu_info->dev, "alloc_l1: get_zeroed_page() = %p\n", pt); + + for (i = 0; i < ISP_L1PT_PTES; i++) + pt[i] = mmu_info->dummy_l2_pteval; + + dma = map_single(mmu_info, pt); + if (!dma) { + dev_err(mmu_info->dev, "Failed to map l1pt page\n"); + goto err_free_page; + } + + mmu_info->l1_pt_dma = dma >> ISP_PADDR_SHIFT; + dev_dbg(mmu_info->dev, "l1 pt %p mapped at %pad\n", pt, &dma); + + return pt; + +err_free_page: + free_page((unsigned long)pt); + return NULL; +} + +static u32 *alloc_l2_pt(struct ipu7_mmu_info *mmu_info) +{ + u32 *pt = (u32 *)get_zeroed_page(GFP_ATOMIC | GFP_DMA32); + unsigned int i; + + if (!pt) + return NULL; + + dev_dbg(mmu_info->dev, "alloc_l2: get_zeroed_page() = %p\n", pt); + + for (i = 0; i < ISP_L1PT_PTES; i++) + pt[i] = mmu_info->dummy_page_pteval; + + return pt; +} + +static void l2_unmap(struct ipu7_mmu_info *mmu_info, unsigned long iova, + phys_addr_t dummy, size_t size) +{ + unsigned int l2_entries; + unsigned int l2_idx; + unsigned long flags; + u32 l1_idx; + u32 *l2_pt; + + spin_lock_irqsave(&mmu_info->lock, flags); + for (l1_idx = iova >> ISP_L1PT_SHIFT; + size > 0U && l1_idx < ISP_L1PT_PTES; l1_idx++) { + dev_dbg(mmu_info->dev, + "unmapping l2 pgtable (l1 index %u (iova 0x%8.8lx))\n", + l1_idx, iova); + + if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) { + dev_err(mmu_info->dev, + "unmap not mapped iova 0x%8.8lx l1 index %u\n", + iova, l1_idx); + continue; + } + l2_pt = mmu_info->l2_pts[l1_idx]; + + l2_entries = 0; + for (l2_idx = (iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT; + size > 0U && l2_idx < ISP_L2PT_PTES; l2_idx++) { + phys_addr_t pteval = TBL_PHYS_ADDR(l2_pt[l2_idx]); + + dev_dbg(mmu_info->dev, + "unmap l2 index %u with pteval 0x%p\n", + l2_idx, &pteval); + l2_pt[l2_idx] = mmu_info->dummy_page_pteval; + + iova += ISP_PAGE_SIZE; + size -= ISP_PAGE_SIZE; + + l2_entries++; + } + + WARN_ON_ONCE(!l2_entries); + clflush_cache_range(&l2_pt[l2_idx - l2_entries], + sizeof(l2_pt[0]) * l2_entries); + } + + WARN_ON_ONCE(size); + spin_unlock_irqrestore(&mmu_info->lock, flags); +} + +static int l2_map(struct ipu7_mmu_info *mmu_info, unsigned long iova, + phys_addr_t paddr, size_t size) +{ + struct device *dev = mmu_info->dev; + unsigned int l2_entries; + u32 *l2_pt, *l2_virt; + unsigned int l2_idx; + unsigned long flags; + size_t mapped = 0; + dma_addr_t dma; + u32 l1_entry; + u32 l1_idx; + int err = 0; + + spin_lock_irqsave(&mmu_info->lock, flags); + + paddr = ALIGN(paddr, ISP_PAGE_SIZE); + for (l1_idx = iova >> ISP_L1PT_SHIFT; + size && l1_idx < ISP_L1PT_PTES; l1_idx++) { + dev_dbg(dev, + "mapping l2 page table for l1 index %u (iova %8.8x)\n", + l1_idx, (u32)iova); + + l1_entry = mmu_info->l1_pt[l1_idx]; + if (l1_entry == mmu_info->dummy_l2_pteval) { + l2_virt = mmu_info->l2_pts[l1_idx]; + if (likely(!l2_virt)) { + l2_virt = alloc_l2_pt(mmu_info); + if (!l2_virt) { + err = -ENOMEM; + goto error; + } + } + + dma = map_single(mmu_info, l2_virt); + if (!dma) { + dev_err(dev, "Failed to map l2pt page\n"); + free_page((unsigned long)l2_virt); + err = -EINVAL; + goto error; + } + + l1_entry = dma >> ISP_PADDR_SHIFT; + + dev_dbg(dev, "page for l1_idx %u %p allocated\n", + l1_idx, l2_virt); + mmu_info->l1_pt[l1_idx] = l1_entry; + mmu_info->l2_pts[l1_idx] = l2_virt; + + clflush_cache_range(&mmu_info->l1_pt[l1_idx], + sizeof(mmu_info->l1_pt[l1_idx])); + } + + l2_pt = mmu_info->l2_pts[l1_idx]; + l2_entries = 0; + + for (l2_idx = (iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT; + size && l2_idx < ISP_L2PT_PTES; l2_idx++) { + l2_pt[l2_idx] = paddr >> ISP_PADDR_SHIFT; + + dev_dbg(dev, "l2 index %u mapped as 0x%8.8x\n", l2_idx, + l2_pt[l2_idx]); + + iova += ISP_PAGE_SIZE; + paddr += ISP_PAGE_SIZE; + mapped += ISP_PAGE_SIZE; + size -= ISP_PAGE_SIZE; + + l2_entries++; + } + + WARN_ON_ONCE(!l2_entries); + clflush_cache_range(&l2_pt[l2_idx - l2_entries], + sizeof(l2_pt[0]) * l2_entries); + } + + spin_unlock_irqrestore(&mmu_info->lock, flags); + + return 0; + +error: + spin_unlock_irqrestore(&mmu_info->lock, flags); + /* unroll mapping in case something went wrong */ + if (mapped) + l2_unmap(mmu_info, iova - mapped, paddr - mapped, mapped); + + return err; +} + +static int __ipu7_mmu_map(struct ipu7_mmu_info *mmu_info, unsigned long iova, + phys_addr_t paddr, size_t size) +{ + u32 iova_start = round_down(iova, ISP_PAGE_SIZE); + u32 iova_end = ALIGN(iova + size, ISP_PAGE_SIZE); + + dev_dbg(mmu_info->dev, + "mapping iova 0x%8.8x--0x%8.8x, size %zu at paddr %pap\n", + iova_start, iova_end, size, &paddr); + + return l2_map(mmu_info, iova_start, paddr, size); +} + +static void __ipu7_mmu_unmap(struct ipu7_mmu_info *mmu_info, + unsigned long iova, size_t size) +{ + l2_unmap(mmu_info, iova, 0, size); +} + +static int allocate_trash_buffer(struct ipu7_mmu *mmu) +{ + unsigned int n_pages = PFN_UP(IPU_MMUV2_TRASH_RANGE); + unsigned long iova_addr; + struct iova *iova; + unsigned int i; + dma_addr_t dma; + int ret; + + /* Allocate 8MB in iova range */ + iova = alloc_iova(&mmu->dmap->iovad, n_pages, + PHYS_PFN(mmu->dmap->mmu_info->aperture_end), 0); + if (!iova) { + dev_err(mmu->dev, "cannot allocate iova range for trash\n"); + return -ENOMEM; + } + + dma = dma_map_page(mmu->dmap->mmu_info->dev, mmu->trash_page, 0, + PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(mmu->dmap->mmu_info->dev, dma)) { + dev_err(mmu->dmap->mmu_info->dev, "Failed to map trash page\n"); + ret = -ENOMEM; + goto out_free_iova; + } + + mmu->pci_trash_page = dma; + + /* + * Map the 8MB iova address range to the same physical trash page + * mmu->trash_page which is already reserved at the probe + */ + iova_addr = iova->pfn_lo; + for (i = 0; i < n_pages; i++) { + ret = ipu7_mmu_map(mmu->dmap->mmu_info, PFN_PHYS(iova_addr), + mmu->pci_trash_page, PAGE_SIZE); + if (ret) { + dev_err(mmu->dev, + "mapping trash buffer range failed\n"); + goto out_unmap; + } + + iova_addr++; + } + + mmu->iova_trash_page = PFN_PHYS(iova->pfn_lo); + dev_dbg(mmu->dev, "iova trash buffer for MMUID: %d is %u\n", + mmu->mmid, (unsigned int)mmu->iova_trash_page); + return 0; + +out_unmap: + ipu7_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo), + PFN_PHYS(iova_size(iova))); + dma_unmap_page(mmu->dmap->mmu_info->dev, mmu->pci_trash_page, + PAGE_SIZE, DMA_BIDIRECTIONAL); +out_free_iova: + __free_iova(&mmu->dmap->iovad, iova); + return ret; +} + +static void __mmu_at_init(struct ipu7_mmu *mmu) +{ + struct ipu7_mmu_info *mmu_info; + unsigned int i; + + mmu_info = mmu->dmap->mmu_info; + for (i = 0; i < mmu->nr_mmus; i++) { + struct ipu7_mmu_hw *mmu_hw = &mmu->mmu_hw[i]; + unsigned int j; + + /* Write page table address per MMU */ + writel((phys_addr_t)mmu_info->l1_pt_dma, + mmu_hw->base + MMU_REG_PAGE_TABLE_BASE_ADDR); + dev_dbg(mmu->dev, "mmu %s base was set as %x\n", mmu_hw->name, + readl(mmu_hw->base + MMU_REG_PAGE_TABLE_BASE_ADDR)); + + /* Set info bits and axi_refill per MMU */ + writel(mmu_hw->info_bits, + mmu_hw->base + MMU_REG_USER_INFO_BITS); + writel(mmu_hw->refill, mmu_hw->base + MMU_REG_AXI_REFILL_IF_ID); + writel(mmu_hw->collapse_en_bitmap, + mmu_hw->base + MMU_REG_COLLAPSE_ENABLE_BITMAP); + + dev_dbg(mmu->dev, "mmu %s info_bits was set as %x\n", + mmu_hw->name, + readl(mmu_hw->base + MMU_REG_USER_INFO_BITS)); + + if (mmu_hw->at_sp_arb_cfg) + writel(mmu_hw->at_sp_arb_cfg, + mmu_hw->base + MMU_REG_AT_SP_ARB_CFG); + + /* default irq configuration */ + writel(0x3ff, mmu_hw->base + MMU_REG_IRQ_MASK); + writel(0x3ff, mmu_hw->base + MMU_REG_IRQ_ENABLE); + + /* Configure MMU TLB stream configuration for L1/L2 */ + for (j = 0; j < mmu_hw->nr_l1streams; j++) { + writel(mmu_hw->l1_block_sz[j], mmu_hw->base + + mmu_hw->l1_block + 4U * j); + } + + for (j = 0; j < mmu_hw->nr_l2streams; j++) { + writel(mmu_hw->l2_block_sz[j], mmu_hw->base + + mmu_hw->l2_block + 4U * j); + } + + for (j = 0; j < mmu_hw->uao_p_num; j++) { + if (!mmu_hw->uao_p2tlb[j]) + continue; + writel(mmu_hw->uao_p2tlb[j], mmu_hw->uao_base + 4U * j); + } + } +} + +static void __mmu_zlx_init(struct ipu7_mmu *mmu) +{ + unsigned int i; + + dev_dbg(mmu->dev, "mmu zlx init\n"); + + for (i = 0; i < mmu->nr_mmus; i++) { + struct ipu7_mmu_hw *mmu_hw = &mmu->mmu_hw[i]; + unsigned int j; + + dev_dbg(mmu->dev, "mmu %s zlx init\n", mmu_hw->name); + for (j = 0; j < IPU_ZLX_POOL_NUM; j++) { + if (!mmu_hw->zlx_axi_pool[j]) + continue; + writel(mmu_hw->zlx_axi_pool[j], + mmu_hw->zlx_base + ZLX_REG_AXI_POOL + j * 0x4U); + } + + for (j = 0; j < mmu_hw->zlx_nr; j++) { + if (!mmu_hw->zlx_conf[j]) + continue; + + writel(mmu_hw->zlx_conf[j], + mmu_hw->zlx_base + ZLX_REG_CONF + j * 0x8U); + } + + for (j = 0; j < mmu_hw->zlx_nr; j++) { + if (!mmu_hw->zlx_en[j]) + continue; + + writel(mmu_hw->zlx_en[j], + mmu_hw->zlx_base + ZLX_REG_EN + j * 0x8U); + } + } +} + +int ipu7_mmu_hw_init(struct ipu7_mmu *mmu) +{ + unsigned long flags; + + dev_dbg(mmu->dev, "IPU mmu hardware init\n"); + + /* Initialise the each MMU and ZLX */ + __mmu_at_init(mmu); + __mmu_zlx_init(mmu); + + if (!mmu->trash_page) { + int ret; + + mmu->trash_page = alloc_page(GFP_KERNEL); + if (!mmu->trash_page) { + dev_err(mmu->dev, "insufficient memory for trash buffer\n"); + return -ENOMEM; + } + + ret = allocate_trash_buffer(mmu); + if (ret) { + __free_page(mmu->trash_page); + mmu->trash_page = NULL; + dev_err(mmu->dev, "trash buffer allocation failed\n"); + return ret; + } + } + + spin_lock_irqsave(&mmu->ready_lock, flags); + mmu->ready = true; + spin_unlock_irqrestore(&mmu->ready_lock, flags); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ipu7_mmu_hw_init, "INTEL_IPU7"); + +static struct ipu7_mmu_info *ipu7_mmu_alloc(struct ipu7_device *isp) +{ + struct ipu7_mmu_info *mmu_info; + int ret; + + mmu_info = kzalloc(sizeof(*mmu_info), GFP_KERNEL); + if (!mmu_info) + return NULL; + + if (isp->secure_mode) { + mmu_info->aperture_start = IPU_FW_CODE_REGION_END; + mmu_info->aperture_end = + (dma_addr_t)DMA_BIT_MASK(IPU_MMU_ADDR_BITS); + } else { + mmu_info->aperture_start = IPU_FW_CODE_REGION_START; + mmu_info->aperture_end = + (dma_addr_t)DMA_BIT_MASK(IPU_MMU_ADDR_BITS_NON_SECURE); + } + + mmu_info->pgsize_bitmap = SZ_4K; + mmu_info->dev = &isp->pdev->dev; + + ret = get_dummy_page(mmu_info); + if (ret) + goto err_free_info; + + ret = alloc_dummy_l2_pt(mmu_info); + if (ret) + goto err_free_dummy_page; + + mmu_info->l2_pts = vzalloc(ISP_L2PT_PTES * sizeof(*mmu_info->l2_pts)); + if (!mmu_info->l2_pts) + goto err_free_dummy_l2_pt; + + /* + * We always map the L1 page table (a single page as well as + * the L2 page tables). + */ + mmu_info->l1_pt = alloc_l1_pt(mmu_info); + if (!mmu_info->l1_pt) + goto err_free_l2_pts; + + spin_lock_init(&mmu_info->lock); + + dev_dbg(mmu_info->dev, "domain initialised\n"); + + return mmu_info; + +err_free_l2_pts: + vfree(mmu_info->l2_pts); +err_free_dummy_l2_pt: + free_dummy_l2_pt(mmu_info); +err_free_dummy_page: + free_dummy_page(mmu_info); +err_free_info: + kfree(mmu_info); + + return NULL; +} + +void ipu7_mmu_hw_cleanup(struct ipu7_mmu *mmu) +{ + unsigned long flags; + + spin_lock_irqsave(&mmu->ready_lock, flags); + mmu->ready = false; + spin_unlock_irqrestore(&mmu->ready_lock, flags); +} +EXPORT_SYMBOL_NS_GPL(ipu7_mmu_hw_cleanup, "INTEL_IPU7"); + +static struct ipu7_dma_mapping *alloc_dma_mapping(struct ipu7_device *isp) +{ + struct ipu7_dma_mapping *dmap; + unsigned long base_pfn; + + dmap = kzalloc(sizeof(*dmap), GFP_KERNEL); + if (!dmap) + return NULL; + + dmap->mmu_info = ipu7_mmu_alloc(isp); + if (!dmap->mmu_info) { + kfree(dmap); + return NULL; + } + + /* 0~64M is forbidden for uctile controller */ + base_pfn = max_t(unsigned long, 1, + PFN_DOWN(dmap->mmu_info->aperture_start)); + init_iova_domain(&dmap->iovad, SZ_4K, base_pfn); + dmap->mmu_info->dmap = dmap; + + dev_dbg(&isp->pdev->dev, "alloc mapping\n"); + + iova_cache_get(); + + return dmap; +} + +phys_addr_t ipu7_mmu_iova_to_phys(struct ipu7_mmu_info *mmu_info, + dma_addr_t iova) +{ + phys_addr_t phy_addr; + unsigned long flags; + u32 *l2_pt; + + spin_lock_irqsave(&mmu_info->lock, flags); + l2_pt = mmu_info->l2_pts[iova >> ISP_L1PT_SHIFT]; + phy_addr = (phys_addr_t)l2_pt[(iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT]; + phy_addr <<= ISP_PAGE_SHIFT; + spin_unlock_irqrestore(&mmu_info->lock, flags); + + return phy_addr; +} + +void ipu7_mmu_unmap(struct ipu7_mmu_info *mmu_info, unsigned long iova, + size_t size) +{ + unsigned int min_pagesz; + + dev_dbg(mmu_info->dev, "unmapping iova 0x%lx size 0x%zx\n", iova, size); + + /* find out the minimum page size supported */ + min_pagesz = 1U << __ffs(mmu_info->pgsize_bitmap); + + /* + * The virtual address and the size of the mapping must be + * aligned (at least) to the size of the smallest page supported + * by the hardware + */ + if (!IS_ALIGNED(iova | size, min_pagesz)) { + dev_err(mmu_info->dev, + "unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n", + iova, size, min_pagesz); + return; + } + + __ipu7_mmu_unmap(mmu_info, iova, size); +} + +int ipu7_mmu_map(struct ipu7_mmu_info *mmu_info, unsigned long iova, + phys_addr_t paddr, size_t size) +{ + unsigned int min_pagesz; + + if (mmu_info->pgsize_bitmap == 0UL) + return -ENODEV; + + /* find out the minimum page size supported */ + min_pagesz = 1U << __ffs(mmu_info->pgsize_bitmap); + + /* + * both the virtual address and the physical one, as well as + * the size of the mapping, must be aligned (at least) to the + * size of the smallest page supported by the hardware + */ + if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) { + dev_err(mmu_info->dev, + "unaligned: iova %lx pa %pa size %zx min_pagesz %x\n", + iova, &paddr, size, min_pagesz); + return -EINVAL; + } + + dev_dbg(mmu_info->dev, "map: iova 0x%lx pa %pa size 0x%zx\n", + iova, &paddr, size); + + return __ipu7_mmu_map(mmu_info, iova, paddr, size); +} + +static void ipu7_mmu_destroy(struct ipu7_mmu *mmu) +{ + struct ipu7_dma_mapping *dmap = mmu->dmap; + struct ipu7_mmu_info *mmu_info = dmap->mmu_info; + struct iova *iova; + u32 l1_idx; + + if (mmu->iova_trash_page) { + iova = find_iova(&dmap->iovad, PHYS_PFN(mmu->iova_trash_page)); + if (iova) { + /* unmap and free the trash buffer iova */ + ipu7_mmu_unmap(mmu_info, PFN_PHYS(iova->pfn_lo), + PFN_PHYS(iova_size(iova))); + __free_iova(&dmap->iovad, iova); + } else { + dev_err(mmu->dev, "trash buffer iova not found.\n"); + } + + mmu->iova_trash_page = 0; + dma_unmap_page(mmu_info->dev, mmu->pci_trash_page, + PAGE_SIZE, DMA_BIDIRECTIONAL); + mmu->pci_trash_page = 0; + __free_page(mmu->trash_page); + } + + for (l1_idx = 0; l1_idx < ISP_L1PT_PTES; l1_idx++) { + if (mmu_info->l1_pt[l1_idx] != mmu_info->dummy_l2_pteval) { + dma_unmap_single(mmu_info->dev, + TBL_PHYS_ADDR(mmu_info->l1_pt[l1_idx]), + PAGE_SIZE, DMA_BIDIRECTIONAL); + free_page((unsigned long)mmu_info->l2_pts[l1_idx]); + } + } + + vfree(mmu_info->l2_pts); + free_dummy_page(mmu_info); + dma_unmap_single(mmu_info->dev, TBL_PHYS_ADDR(mmu_info->l1_pt_dma), + PAGE_SIZE, DMA_BIDIRECTIONAL); + free_page((unsigned long)mmu_info->dummy_l2_pt); + free_page((unsigned long)mmu_info->l1_pt); + kfree(mmu_info); +} + +struct ipu7_mmu *ipu7_mmu_init(struct device *dev, + void __iomem *base, int mmid, + const struct ipu7_hw_variants *hw) +{ + struct ipu7_device *isp = pci_get_drvdata(to_pci_dev(dev)); + struct ipu7_mmu_pdata *pdata; + struct ipu7_mmu *mmu; + unsigned int i; + + if (hw->nr_mmus > IPU_MMU_MAX_NUM) + return ERR_PTR(-EINVAL); + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < hw->nr_mmus; i++) { + struct ipu7_mmu_hw *pdata_mmu = &pdata->mmu_hw[i]; + const struct ipu7_mmu_hw *src_mmu = &hw->mmu_hw[i]; + + if (src_mmu->nr_l1streams > IPU_MMU_MAX_TLB_L1_STREAMS || + src_mmu->nr_l2streams > IPU_MMU_MAX_TLB_L2_STREAMS) + return ERR_PTR(-EINVAL); + + *pdata_mmu = *src_mmu; + pdata_mmu->base = base + src_mmu->offset; + pdata_mmu->zlx_base = base + src_mmu->zlx_offset; + pdata_mmu->uao_base = base + src_mmu->uao_offset; + } + + mmu = devm_kzalloc(dev, sizeof(*mmu), GFP_KERNEL); + if (!mmu) + return ERR_PTR(-ENOMEM); + + mmu->mmid = mmid; + mmu->mmu_hw = pdata->mmu_hw; + mmu->nr_mmus = hw->nr_mmus; + mmu->tlb_invalidate = tlb_invalidate; + mmu->ready = false; + INIT_LIST_HEAD(&mmu->vma_list); + spin_lock_init(&mmu->ready_lock); + + mmu->dmap = alloc_dma_mapping(isp); + if (!mmu->dmap) { + dev_err(dev, "can't alloc dma mapping\n"); + return ERR_PTR(-ENOMEM); + } + + return mmu; +} + +void ipu7_mmu_cleanup(struct ipu7_mmu *mmu) +{ + struct ipu7_dma_mapping *dmap = mmu->dmap; + + ipu7_mmu_destroy(mmu); + mmu->dmap = NULL; + iova_cache_put(); + put_iova_domain(&dmap->iovad); + kfree(dmap); +} diff --git a/drivers/staging/media/ipu7/ipu7-mmu.h b/drivers/staging/media/ipu7/ipu7-mmu.h new file mode 100644 index 0000000000000..d85bb8ffc711f --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-mmu.h @@ -0,0 +1,414 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#ifndef IPU7_MMU_H +#define IPU7_MMU_H + +#include <linux/dma-mapping.h> +#include <linux/list.h> +#include <linux/spinlock_types.h> +#include <linux/types.h> + +struct device; +struct page; +struct ipu7_hw_variants; +struct ipu7_mmu; +struct ipu7_mmu_info; + +#define ISYS_MMID 0x1 +#define PSYS_MMID 0x0 + +/* IPU7 for LNL */ +/* IS MMU Cmd RD */ +#define IPU7_IS_MMU_FW_RD_OFFSET 0x274000 +#define IPU7_IS_MMU_FW_RD_STREAM_NUM 3 +#define IPU7_IS_MMU_FW_RD_L1_BLOCKNR_REG 0x54 +#define IPU7_IS_MMU_FW_RD_L2_BLOCKNR_REG 0x60 + +/* IS MMU Cmd WR */ +#define IPU7_IS_MMU_FW_WR_OFFSET 0x275000 +#define IPU7_IS_MMU_FW_WR_STREAM_NUM 3 +#define IPU7_IS_MMU_FW_WR_L1_BLOCKNR_REG 0x54 +#define IPU7_IS_MMU_FW_WR_L2_BLOCKNR_REG 0x60 + +/* IS MMU Data WR Snoop */ +#define IPU7_IS_MMU_M0_OFFSET 0x276000 +#define IPU7_IS_MMU_M0_STREAM_NUM 8 +#define IPU7_IS_MMU_M0_L1_BLOCKNR_REG 0x54 +#define IPU7_IS_MMU_M0_L2_BLOCKNR_REG 0x74 + +/* IS MMU Data WR ISOC */ +#define IPU7_IS_MMU_M1_OFFSET 0x277000 +#define IPU7_IS_MMU_M1_STREAM_NUM 16 +#define IPU7_IS_MMU_M1_L1_BLOCKNR_REG 0x54 +#define IPU7_IS_MMU_M1_L2_BLOCKNR_REG 0x94 + +/* PS MMU FW RD */ +#define IPU7_PS_MMU_FW_RD_OFFSET 0x148000 +#define IPU7_PS_MMU_FW_RD_STREAM_NUM 20 +#define IPU7_PS_MMU_FW_RD_L1_BLOCKNR_REG 0x54 +#define IPU7_PS_MMU_FW_RD_L2_BLOCKNR_REG 0xa4 + +/* PS MMU FW WR */ +#define IPU7_PS_MMU_FW_WR_OFFSET 0x149000 +#define IPU7_PS_MMU_FW_WR_STREAM_NUM 10 +#define IPU7_PS_MMU_FW_WR_L1_BLOCKNR_REG 0x54 +#define IPU7_PS_MMU_FW_WR_L2_BLOCKNR_REG 0x7c + +/* PS MMU FW Data RD VC0 */ +#define IPU7_PS_MMU_SRT_RD_OFFSET 0x14a000 +#define IPU7_PS_MMU_SRT_RD_STREAM_NUM 40 +#define IPU7_PS_MMU_SRT_RD_L1_BLOCKNR_REG 0x54 +#define IPU7_PS_MMU_SRT_RD_L2_BLOCKNR_REG 0xf4 + +/* PS MMU FW Data WR VC0 */ +#define IPU7_PS_MMU_SRT_WR_OFFSET 0x14b000 +#define IPU7_PS_MMU_SRT_WR_STREAM_NUM 40 +#define IPU7_PS_MMU_SRT_WR_L1_BLOCKNR_REG 0x54 +#define IPU7_PS_MMU_SRT_WR_L2_BLOCKNR_REG 0xf4 + +/* IS UAO UC RD */ +#define IPU7_IS_UAO_UC_RD_OFFSET 0x27c000 +#define IPU7_IS_UAO_UC_RD_PLANENUM 4 + +/* IS UAO UC WR */ +#define IPU7_IS_UAO_UC_WR_OFFSET 0x27d000 +#define IPU7_IS_UAO_UC_WR_PLANENUM 4 + +/* IS UAO M0 WR */ +#define IPU7_IS_UAO_M0_WR_OFFSET 0x27e000 +#define IPU7_IS_UAO_M0_WR_PLANENUM 8 + +/* IS UAO M1 WR */ +#define IPU7_IS_UAO_M1_WR_OFFSET 0x27f000 +#define IPU7_IS_UAO_M1_WR_PLANENUM 16 + +/* PS UAO FW RD */ +#define IPU7_PS_UAO_FW_RD_OFFSET 0x156000 +#define IPU7_PS_UAO_FW_RD_PLANENUM 20 + +/* PS UAO FW WR */ +#define IPU7_PS_UAO_FW_WR_OFFSET 0x157000 +#define IPU7_PS_UAO_FW_WR_PLANENUM 16 + +/* PS UAO SRT RD */ +#define IPU7_PS_UAO_SRT_RD_OFFSET 0x154000 +#define IPU7_PS_UAO_SRT_RD_PLANENUM 40 + +/* PS UAO SRT WR */ +#define IPU7_PS_UAO_SRT_WR_OFFSET 0x155000 +#define IPU7_PS_UAO_SRT_WR_PLANENUM 40 + +#define IPU7_IS_ZLX_UC_RD_OFFSET 0x278000 +#define IPU7_IS_ZLX_UC_WR_OFFSET 0x279000 +#define IPU7_IS_ZLX_M0_OFFSET 0x27a000 +#define IPU7_IS_ZLX_M1_OFFSET 0x27b000 +#define IPU7_IS_ZLX_UC_RD_NUM 4 +#define IPU7_IS_ZLX_UC_WR_NUM 4 +#define IPU7_IS_ZLX_M0_NUM 8 +#define IPU7_IS_ZLX_M1_NUM 16 + +#define IPU7_PS_ZLX_DATA_RD_OFFSET 0x14e000 +#define IPU7_PS_ZLX_DATA_WR_OFFSET 0x14f000 +#define IPU7_PS_ZLX_FW_RD_OFFSET 0x150000 +#define IPU7_PS_ZLX_FW_WR_OFFSET 0x151000 +#define IPU7_PS_ZLX_DATA_RD_NUM 32 +#define IPU7_PS_ZLX_DATA_WR_NUM 32 +#define IPU7_PS_ZLX_FW_RD_NUM 16 +#define IPU7_PS_ZLX_FW_WR_NUM 10 + +/* IPU7P5 for PTL */ +/* IS MMU Cmd RD */ +#define IPU7P5_IS_MMU_FW_RD_OFFSET 0x274000 +#define IPU7P5_IS_MMU_FW_RD_STREAM_NUM 3 +#define IPU7P5_IS_MMU_FW_RD_L1_BLOCKNR_REG 0x54 +#define IPU7P5_IS_MMU_FW_RD_L2_BLOCKNR_REG 0x60 + +/* IS MMU Cmd WR */ +#define IPU7P5_IS_MMU_FW_WR_OFFSET 0x275000 +#define IPU7P5_IS_MMU_FW_WR_STREAM_NUM 3 +#define IPU7P5_IS_MMU_FW_WR_L1_BLOCKNR_REG 0x54 +#define IPU7P5_IS_MMU_FW_WR_L2_BLOCKNR_REG 0x60 + +/* IS MMU Data WR Snoop */ +#define IPU7P5_IS_MMU_M0_OFFSET 0x276000 +#define IPU7P5_IS_MMU_M0_STREAM_NUM 16 +#define IPU7P5_IS_MMU_M0_L1_BLOCKNR_REG 0x54 +#define IPU7P5_IS_MMU_M0_L2_BLOCKNR_REG 0x94 + +/* IS MMU Data WR ISOC */ +#define IPU7P5_IS_MMU_M1_OFFSET 0x277000 +#define IPU7P5_IS_MMU_M1_STREAM_NUM 16 +#define IPU7P5_IS_MMU_M1_L1_BLOCKNR_REG 0x54 +#define IPU7P5_IS_MMU_M1_L2_BLOCKNR_REG 0x94 + +/* PS MMU FW RD */ +#define IPU7P5_PS_MMU_FW_RD_OFFSET 0x148000 +#define IPU7P5_PS_MMU_FW_RD_STREAM_NUM 16 +#define IPU7P5_PS_MMU_FW_RD_L1_BLOCKNR_REG 0x54 +#define IPU7P5_PS_MMU_FW_RD_L2_BLOCKNR_REG 0x94 + +/* PS MMU FW WR */ +#define IPU7P5_PS_MMU_FW_WR_OFFSET 0x149000 +#define IPU7P5_PS_MMU_FW_WR_STREAM_NUM 10 +#define IPU7P5_PS_MMU_FW_WR_L1_BLOCKNR_REG 0x54 +#define IPU7P5_PS_MMU_FW_WR_L2_BLOCKNR_REG 0x7c + +/* PS MMU FW Data RD VC0 */ +#define IPU7P5_PS_MMU_SRT_RD_OFFSET 0x14a000 +#define IPU7P5_PS_MMU_SRT_RD_STREAM_NUM 22 +#define IPU7P5_PS_MMU_SRT_RD_L1_BLOCKNR_REG 0x54 +#define IPU7P5_PS_MMU_SRT_RD_L2_BLOCKNR_REG 0xac + +/* PS MMU FW Data WR VC0 */ +#define IPU7P5_PS_MMU_SRT_WR_OFFSET 0x14b000 +#define IPU7P5_PS_MMU_SRT_WR_STREAM_NUM 32 +#define IPU7P5_PS_MMU_SRT_WR_L1_BLOCKNR_REG 0x54 +#define IPU7P5_PS_MMU_SRT_WR_L2_BLOCKNR_REG 0xd4 + +/* IS UAO UC RD */ +#define IPU7P5_IS_UAO_UC_RD_OFFSET 0x27c000 +#define IPU7P5_IS_UAO_UC_RD_PLANENUM 4 + +/* IS UAO UC WR */ +#define IPU7P5_IS_UAO_UC_WR_OFFSET 0x27d000 +#define IPU7P5_IS_UAO_UC_WR_PLANENUM 4 + +/* IS UAO M0 WR */ +#define IPU7P5_IS_UAO_M0_WR_OFFSET 0x27e000 +#define IPU7P5_IS_UAO_M0_WR_PLANENUM 16 + +/* IS UAO M1 WR */ +#define IPU7P5_IS_UAO_M1_WR_OFFSET 0x27f000 +#define IPU7P5_IS_UAO_M1_WR_PLANENUM 16 + +/* PS UAO FW RD */ +#define IPU7P5_PS_UAO_FW_RD_OFFSET 0x156000 +#define IPU7P5_PS_UAO_FW_RD_PLANENUM 16 + +/* PS UAO FW WR */ +#define IPU7P5_PS_UAO_FW_WR_OFFSET 0x157000 +#define IPU7P5_PS_UAO_FW_WR_PLANENUM 10 + +/* PS UAO SRT RD */ +#define IPU7P5_PS_UAO_SRT_RD_OFFSET 0x154000 +#define IPU7P5_PS_UAO_SRT_RD_PLANENUM 22 + +/* PS UAO SRT WR */ +#define IPU7P5_PS_UAO_SRT_WR_OFFSET 0x155000 +#define IPU7P5_PS_UAO_SRT_WR_PLANENUM 32 + +#define IPU7P5_IS_ZLX_UC_RD_OFFSET 0x278000 +#define IPU7P5_IS_ZLX_UC_WR_OFFSET 0x279000 +#define IPU7P5_IS_ZLX_M0_OFFSET 0x27a000 +#define IPU7P5_IS_ZLX_M1_OFFSET 0x27b000 +#define IPU7P5_IS_ZLX_UC_RD_NUM 4 +#define IPU7P5_IS_ZLX_UC_WR_NUM 4 +#define IPU7P5_IS_ZLX_M0_NUM 16 +#define IPU7P5_IS_ZLX_M1_NUM 16 + +#define IPU7P5_PS_ZLX_DATA_RD_OFFSET 0x14e000 +#define IPU7P5_PS_ZLX_DATA_WR_OFFSET 0x14f000 +#define IPU7P5_PS_ZLX_FW_RD_OFFSET 0x150000 +#define IPU7P5_PS_ZLX_FW_WR_OFFSET 0x151000 +#define IPU7P5_PS_ZLX_DATA_RD_NUM 22 +#define IPU7P5_PS_ZLX_DATA_WR_NUM 32 +#define IPU7P5_PS_ZLX_FW_RD_NUM 16 +#define IPU7P5_PS_ZLX_FW_WR_NUM 10 + +/* IS MMU Cmd RD */ +#define IPU8_IS_MMU_FW_RD_OFFSET 0x270000 +#define IPU8_IS_MMU_FW_RD_STREAM_NUM 3 +#define IPU8_IS_MMU_FW_RD_L1_BLOCKNR_REG 0x54 +#define IPU8_IS_MMU_FW_RD_L2_BLOCKNR_REG 0x60 + +/* IS MMU Cmd WR */ +#define IPU8_IS_MMU_FW_WR_OFFSET 0x271000 +#define IPU8_IS_MMU_FW_WR_STREAM_NUM 3 +#define IPU8_IS_MMU_FW_WR_L1_BLOCKNR_REG 0x54 +#define IPU8_IS_MMU_FW_WR_L2_BLOCKNR_REG 0x60 + +/* IS MMU Data WR Snoop */ +#define IPU8_IS_MMU_M0_OFFSET 0x272000 +#define IPU8_IS_MMU_M0_STREAM_NUM 16 +#define IPU8_IS_MMU_M0_L1_BLOCKNR_REG 0x54 +#define IPU8_IS_MMU_M0_L2_BLOCKNR_REG 0x94 + +/* IS MMU Data WR ISOC */ +#define IPU8_IS_MMU_M1_OFFSET 0x273000 +#define IPU8_IS_MMU_M1_STREAM_NUM 16 +#define IPU8_IS_MMU_M1_L1_BLOCKNR_REG 0x54 +#define IPU8_IS_MMU_M1_L2_BLOCKNR_REG 0x94 + +/* IS MMU UPIPE ISOC */ +#define IPU8_IS_MMU_UPIPE_OFFSET 0x274000 +#define IPU8_IS_MMU_UPIPE_STREAM_NUM 6 +#define IPU8_IS_MMU_UPIPE_L1_BLOCKNR_REG 0x54 +#define IPU8_IS_MMU_UPIPE_L2_BLOCKNR_REG 0x6c + +/* PS MMU FW RD */ +#define IPU8_PS_MMU_FW_RD_OFFSET 0x148000 +#define IPU8_PS_MMU_FW_RD_STREAM_NUM 12 +#define IPU8_PS_MMU_FW_RD_L1_BLOCKNR_REG 0x54 +#define IPU8_PS_MMU_FW_RD_L2_BLOCKNR_REG 0x84 + +/* PS MMU FW WR */ +#define IPU8_PS_MMU_FW_WR_OFFSET 0x149000 +#define IPU8_PS_MMU_FW_WR_STREAM_NUM 8 +#define IPU8_PS_MMU_FW_WR_L1_BLOCKNR_REG 0x54 +#define IPU8_PS_MMU_FW_WR_L2_BLOCKNR_REG 0x74 + +/* PS MMU FW Data RD VC0 */ +#define IPU8_PS_MMU_SRT_RD_OFFSET 0x14a000 +#define IPU8_PS_MMU_SRT_RD_STREAM_NUM 26 +#define IPU8_PS_MMU_SRT_RD_L1_BLOCKNR_REG 0x54 +#define IPU8_PS_MMU_SRT_RD_L2_BLOCKNR_REG 0xbc + +/* PS MMU FW Data WR VC0 */ +#define IPU8_PS_MMU_SRT_WR_OFFSET 0x14b000 +#define IPU8_PS_MMU_SRT_WR_STREAM_NUM 26 +#define IPU8_PS_MMU_SRT_WR_L1_BLOCKNR_REG 0x54 +#define IPU8_PS_MMU_SRT_WR_L2_BLOCKNR_REG 0xbc + +/* IS UAO UC RD */ +#define IPU8_IS_UAO_UC_RD_OFFSET 0x27a000 +#define IPU8_IS_UAO_UC_RD_PLANENUM 4 + +/* IS UAO UC WR */ +#define IPU8_IS_UAO_UC_WR_OFFSET 0x27b000 +#define IPU8_IS_UAO_UC_WR_PLANENUM 4 + +/* IS UAO M0 WR */ +#define IPU8_IS_UAO_M0_WR_OFFSET 0x27c000 +#define IPU8_IS_UAO_M0_WR_PLANENUM 16 + +/* IS UAO M1 WR */ +#define IPU8_IS_UAO_M1_WR_OFFSET 0x27d000 +#define IPU8_IS_UAO_M1_WR_PLANENUM 16 + +/* IS UAO UPIPE */ +#define IPU8_IS_UAO_UPIPE_OFFSET 0x27e000 +#define IPU8_IS_UAO_UPIPE_PLANENUM 6 + +/* PS UAO FW RD */ +#define IPU8_PS_UAO_FW_RD_OFFSET 0x156000 +#define IPU8_PS_UAO_FW_RD_PLANENUM 12 + +/* PS UAO FW WR */ +#define IPU8_PS_UAO_FW_WR_OFFSET 0x157000 +#define IPU8_PS_UAO_FW_WR_PLANENUM 8 + +/* PS UAO SRT RD */ +#define IPU8_PS_UAO_SRT_RD_OFFSET 0x154000 +#define IPU8_PS_UAO_SRT_RD_PLANENUM 26 + +/* PS UAO SRT WR */ +#define IPU8_PS_UAO_SRT_WR_OFFSET 0x155000 +#define IPU8_PS_UAO_SRT_WR_PLANENUM 26 + +#define IPU8_IS_ZLX_UC_RD_OFFSET 0x275000 +#define IPU8_IS_ZLX_UC_WR_OFFSET 0x276000 +#define IPU8_IS_ZLX_M0_OFFSET 0x277000 +#define IPU8_IS_ZLX_M1_OFFSET 0x278000 +#define IPU8_IS_ZLX_UPIPE_OFFSET 0x279000 +#define IPU8_IS_ZLX_UC_RD_NUM 4 +#define IPU8_IS_ZLX_UC_WR_NUM 4 +#define IPU8_IS_ZLX_M0_NUM 16 +#define IPU8_IS_ZLX_M1_NUM 16 +#define IPU8_IS_ZLX_UPIPE_NUM 6 + +#define IPU8_PS_ZLX_DATA_RD_OFFSET 0x14e000 +#define IPU8_PS_ZLX_DATA_WR_OFFSET 0x14f000 +#define IPU8_PS_ZLX_FW_RD_OFFSET 0x150000 +#define IPU8_PS_ZLX_FW_WR_OFFSET 0x151000 +#define IPU8_PS_ZLX_DATA_RD_NUM 26 +#define IPU8_PS_ZLX_DATA_WR_NUM 26 +#define IPU8_PS_ZLX_FW_RD_NUM 12 +#define IPU8_PS_ZLX_FW_WR_NUM 8 + +#define MMU_REG_INVALIDATE_0 0x00 +#define MMU_REG_INVALIDATE_1 0x04 +#define MMU_REG_PAGE_TABLE_BASE_ADDR 0x08 +#define MMU_REG_USER_INFO_BITS 0x0c +#define MMU_REG_AXI_REFILL_IF_ID 0x10 +#define MMU_REG_PW_EN_BITMAP 0x14 +#define MMU_REG_COLLAPSE_ENABLE_BITMAP 0x18 +#define MMU_REG_GENERAL_REG 0x1c +#define MMU_REG_AT_SP_ARB_CFG 0x20 +#define MMU_REG_INVALIDATION_STATUS 0x24 +#define MMU_REG_IRQ_LEVEL_NO_PULSE 0x28 +#define MMU_REG_IRQ_MASK 0x2c +#define MMU_REG_IRQ_ENABLE 0x30 +#define MMU_REG_IRQ_EDGE 0x34 +#define MMU_REG_IRQ_CLEAR 0x38 +#define MMU_REG_IRQ_CAUSE 0x3c +#define MMU_REG_CG_CTRL_BITS 0x40 +#define MMU_REG_RD_FIFOS_STATUS 0x44 +#define MMU_REG_WR_FIFOS_STATUS 0x48 +#define MMU_REG_COMMON_FIFOS_STATUS 0x4c +#define MMU_REG_FSM_STATUS 0x50 + +#define ZLX_REG_AXI_POOL 0x0 +#define ZLX_REG_EN 0x20 +#define ZLX_REG_CONF 0x24 +#define ZLX_REG_CG_CTRL 0x900 +#define ZLX_REG_FORCE_BYPASS 0x904 + +struct ipu7_mmu_info { + struct device *dev; + + u32 *l1_pt; + u32 l1_pt_dma; + u32 **l2_pts; + + u32 *dummy_l2_pt; + u32 dummy_l2_pteval; + void *dummy_page; + u32 dummy_page_pteval; + + dma_addr_t aperture_start; + dma_addr_t aperture_end; + unsigned long pgsize_bitmap; + + spinlock_t lock; /* Serialize access to users */ + struct ipu7_dma_mapping *dmap; +}; + +struct ipu7_mmu { + struct list_head node; + + struct ipu7_mmu_hw *mmu_hw; + unsigned int nr_mmus; + unsigned int mmid; + + phys_addr_t pgtbl; + struct device *dev; + + struct ipu7_dma_mapping *dmap; + struct list_head vma_list; + + struct page *trash_page; + dma_addr_t pci_trash_page; /* IOVA from PCI DMA services (parent) */ + dma_addr_t iova_trash_page; /* IOVA for IPU child nodes to use */ + + bool ready; + spinlock_t ready_lock; /* Serialize access to bool ready */ + + void (*tlb_invalidate)(struct ipu7_mmu *mmu); +}; + +struct ipu7_mmu *ipu7_mmu_init(struct device *dev, + void __iomem *base, int mmid, + const struct ipu7_hw_variants *hw); +void ipu7_mmu_cleanup(struct ipu7_mmu *mmu); +int ipu7_mmu_hw_init(struct ipu7_mmu *mmu); +void ipu7_mmu_hw_cleanup(struct ipu7_mmu *mmu); +int ipu7_mmu_map(struct ipu7_mmu_info *mmu_info, unsigned long iova, + phys_addr_t paddr, size_t size); +void ipu7_mmu_unmap(struct ipu7_mmu_info *mmu_info, unsigned long iova, + size_t size); +phys_addr_t ipu7_mmu_iova_to_phys(struct ipu7_mmu_info *mmu_info, + dma_addr_t iova); +#endif diff --git a/drivers/staging/media/ipu7/ipu7-platform-regs.h b/drivers/staging/media/ipu7/ipu7-platform-regs.h new file mode 100644 index 0000000000000..eeadc886a8cfd --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-platform-regs.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2018 - 2025 Intel Corporation + */ + +#ifndef IPU7_PLATFORM_REGS_H +#define IPU7_PLATFORM_REGS_H + +#define IS_BASE 0x230000 +#define IS_UC_CTRL_BASE (IS_BASE + 0x0) + +#define PS_BASE 0x130000 +#define PS_UC_CTRL_BASE (PS_BASE + 0x0) + +/* + * bit 0: IRQ from FW, + * bit 1, 2 and 3: IRQ from HW + */ +#define TO_SW_IRQ_MASK 0xf +#define TO_SW_IRQ_FW BIT(0) + +#define FW_CODE_BASE 0x0 +#define FW_DATA_BASE 0x4 +#define PRINTF_EN_THROUGH_TRACE 0x3004 +#define PRINTF_EN_DIRECTLY_TO_DDR 0x3008 +#define PRINTF_DDR_BASE_ADDR 0x300c +#define PRINTF_DDR_SIZE 0x3010 +#define PRINTF_DDR_NEXT_ADDR 0x3014 +#define PRINTF_STATUS 0x3018 +#define PRINTF_AXI_CNTL 0x301c +#define PRINTF_MSG_LENGTH 0x3020 +#define TO_SW_IRQ_CNTL_EDGE 0x4000 +#define TO_SW_IRQ_CNTL_MASK_N 0x4004 +#define TO_SW_IRQ_CNTL_STATUS 0x4008 +#define TO_SW_IRQ_CNTL_CLEAR 0x400c +#define TO_SW_IRQ_CNTL_ENABLE 0x4010 +#define TO_SW_IRQ_CNTL_LEVEL_NOT_PULSE 0x4014 +#define ERR_IRQ_CNTL_EDGE 0x4018 +#define ERR_IRQ_CNTL_MASK_N 0x401c +#define ERR_IRQ_CNTL_STATUS 0x4020 +#define ERR_IRQ_CNTL_CLEAR 0x4024 +#define ERR_IRQ_CNTL_ENABLE 0x4028 +#define ERR_IRQ_CNTL_LEVEL_NOT_PULSE 0x402c +#define LOCAL_DMEM_BASE_ADDR 0x1300000 + +/* + * IS_UC_TO_SW irqs + * bit 0: IRQ from local FW + * bit 1~3: IRQ from HW + */ +#define IS_UC_TO_SW_IRQ_MASK 0xf + +#define IPU_ISYS_SPC_OFFSET 0x210000 +#define IPU7_PSYS_SPC_OFFSET 0x118000 +#define IPU_ISYS_DMEM_OFFSET 0x200000 +#define IPU_PSYS_DMEM_OFFSET 0x100000 + +#define IPU7_ISYS_CSI_PORT_NUM 4 + +/* IRQ-related registers in PSYS */ +#define IPU_REG_PSYS_TO_SW_IRQ_CNTL_EDGE 0x134000 +#define IPU_REG_PSYS_TO_SW_IRQ_CNTL_MASK 0x134004 +#define IPU_REG_PSYS_TO_SW_IRQ_CNTL_STATUS 0x134008 +#define IPU_REG_PSYS_TO_SW_IRQ_CNTL_CLEAR 0x13400c +#define IPU_REG_PSYS_TO_SW_IRQ_CNTL_ENABLE 0x134010 +#define IPU_REG_PSYS_TO_SW_IRQ_CNTL_LEVEL_NOT_PULSE 0x134014 +#define IRQ_FROM_LOCAL_FW BIT(0) + +/* + * psys subdomains power request regs + */ +enum ipu7_device_buttress_psys_domain_pos { + IPU_PSYS_SUBDOMAIN_LB = 0, + IPU_PSYS_SUBDOMAIN_BB = 1, +}; + +#define IPU7_PSYS_DOMAIN_POWER_MASK (BIT(IPU_PSYS_SUBDOMAIN_LB) | \ + BIT(IPU_PSYS_SUBDOMAIN_BB)) +#define IPU8_PSYS_DOMAIN_POWER_MASK BIT(IPU_PSYS_SUBDOMAIN_LB) +#define IPU_PSYS_DOMAIN_POWER_IN_PROGRESS BIT(31) + +#endif /* IPU7_PLATFORM_REGS_H */ diff --git a/drivers/staging/media/ipu7/ipu7-syscom.c b/drivers/staging/media/ipu7/ipu7-syscom.c new file mode 100644 index 0000000000000..3f9f9c5c3ccee --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-syscom.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <linux/export.h> +#include <linux/io.h> + +#include "abi/ipu7_fw_syscom_abi.h" + +#include "ipu7.h" +#include "ipu7-syscom.h" + +static void __iomem *ipu7_syscom_get_indices(struct ipu7_syscom_context *ctx, + u32 q) +{ + return ctx->queue_indices + (q * sizeof(struct syscom_queue_indices_s)); +} + +void *ipu7_syscom_get_token(struct ipu7_syscom_context *ctx, int q) +{ + struct syscom_queue_config *queue_params = &ctx->queue_configs[q]; + void __iomem *queue_indices = ipu7_syscom_get_indices(ctx, q); + u32 write_index = readl(queue_indices + + offsetof(struct syscom_queue_indices_s, + write_index)); + u32 read_index = readl(queue_indices + + offsetof(struct syscom_queue_indices_s, + read_index)); + void *token = NULL; + + if (q < ctx->num_output_queues) { + /* Output queue */ + bool empty = (write_index == read_index); + + if (!empty) + token = queue_params->token_array_mem + + read_index * + queue_params->token_size_in_bytes; + } else { + /* Input queue */ + bool full = (read_index == ((write_index + 1U) % + (u32)queue_params->max_capacity)); + + if (!full) + token = queue_params->token_array_mem + + write_index * queue_params->token_size_in_bytes; + } + return token; +} +EXPORT_SYMBOL_NS_GPL(ipu7_syscom_get_token, "INTEL_IPU7"); + +void ipu7_syscom_put_token(struct ipu7_syscom_context *ctx, int q) +{ + struct syscom_queue_config *queue_params = &ctx->queue_configs[q]; + void __iomem *queue_indices = ipu7_syscom_get_indices(ctx, q); + u32 offset, index; + + if (q < ctx->num_output_queues) + /* Output queue */ + offset = offsetof(struct syscom_queue_indices_s, read_index); + + else + /* Input queue */ + offset = offsetof(struct syscom_queue_indices_s, write_index); + + index = readl(queue_indices + offset); + writel((index + 1U) % queue_params->max_capacity, + queue_indices + offset); +} +EXPORT_SYMBOL_NS_GPL(ipu7_syscom_put_token, "INTEL_IPU7"); + +struct syscom_queue_params_config * +ipu7_syscom_get_queue_config(struct syscom_config_s *config) +{ + return (struct syscom_queue_params_config *)(&config[1]); +} +EXPORT_SYMBOL_NS_GPL(ipu7_syscom_get_queue_config, "INTEL_IPU7"); diff --git a/drivers/staging/media/ipu7/ipu7-syscom.h b/drivers/staging/media/ipu7/ipu7-syscom.h new file mode 100644 index 0000000000000..e1fbe3b7914e4 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7-syscom.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#ifndef IPU7_SYSCOM_H +#define IPU7_SYSCOM_H + +#include <linux/types.h> + +struct syscom_config_s; +struct syscom_queue_params_config; + +struct syscom_queue_config { + void *token_array_mem; + u32 queue_size; + u16 token_size_in_bytes; + u16 max_capacity; +}; + +struct ipu7_syscom_context { + u16 num_input_queues; + u16 num_output_queues; + struct syscom_queue_config *queue_configs; + void __iomem *queue_indices; + dma_addr_t queue_mem_dma_addr; + void *queue_mem; + u32 queue_mem_size; +}; + +void ipu7_syscom_put_token(struct ipu7_syscom_context *ctx, int q); +void *ipu7_syscom_get_token(struct ipu7_syscom_context *ctx, int q); +struct syscom_queue_params_config * +ipu7_syscom_get_queue_config(struct syscom_config_s *config); +#endif diff --git a/drivers/staging/media/ipu7/ipu7.c b/drivers/staging/media/ipu7/ipu7.c new file mode 100644 index 0000000000000..1b4f01db13ca2 --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7.c @@ -0,0 +1,2783 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#include <linux/acpi.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/bug.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/firmware.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/property.h> +#include <linux/scatterlist.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/vmalloc.h> +#include <linux/version.h> + +#include <media/ipu-bridge.h> + +#include "abi/ipu7_fw_common_abi.h" + +#include "ipu7.h" +#include "ipu7-bus.h" +#include "ipu7-buttress.h" +#include "ipu7-buttress-regs.h" +#include "ipu7-cpd.h" +#include "ipu7-dma.h" +#include "ipu7-isys-csi2-regs.h" +#include "ipu7-mmu.h" +#include "ipu7-platform-regs.h" + +#define IPU_PCI_BAR 0 +#define IPU_PCI_PBBAR 4 + +static const unsigned int ipu7_csi_offsets[] = { + IPU_CSI_PORT_A_ADDR_OFFSET, + IPU_CSI_PORT_B_ADDR_OFFSET, + IPU_CSI_PORT_C_ADDR_OFFSET, + IPU_CSI_PORT_D_ADDR_OFFSET, +}; + +static struct ipu_isys_internal_pdata ipu7p5_isys_ipdata = { + .csi2 = { + .gpreg = IS_IO_CSI2_GPREGS_BASE, + }, + .hw_variant = { + .offset = IPU_UNIFIED_OFFSET, + .nr_mmus = IPU7P5_IS_MMU_NUM, + .mmu_hw = { + { + .name = "IS_FW_RD", + .offset = IPU7P5_IS_MMU_FW_RD_OFFSET, + .zlx_offset = IPU7P5_IS_ZLX_UC_RD_OFFSET, + .uao_offset = IPU7P5_IS_UAO_UC_RD_OFFSET, + .info_bits = 0x20005101, + .refill = 0x00002726, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU7P5_IS_MMU_FW_RD_L1_BLOCKNR_REG, + .l2_block = IPU7P5_IS_MMU_FW_RD_L2_BLOCKNR_REG, + .nr_l1streams = IPU7P5_IS_MMU_FW_RD_STREAM_NUM, + .nr_l2streams = IPU7P5_IS_MMU_FW_RD_STREAM_NUM, + .l1_block_sz = { + 0x0, 0x8, 0xa, + }, + .l2_block_sz = { + 0x0, 0x2, 0x4, + }, + .zlx_nr = IPU7P5_IS_ZLX_UC_RD_NUM, + .zlx_axi_pool = { + 0x00000f30, + }, + .zlx_en = { + 0, 1, 0, 0 + }, + .zlx_conf = { + 0x0, + }, + .uao_p_num = IPU7P5_IS_UAO_UC_RD_PLANENUM, + .uao_p2tlb = { + 0x00000049, + 0x0000004c, + 0x0000004d, + 0x00000000, + }, + }, + { + .name = "IS_FW_WR", + .offset = IPU7P5_IS_MMU_FW_WR_OFFSET, + .zlx_offset = IPU7P5_IS_ZLX_UC_WR_OFFSET, + .uao_offset = IPU7P5_IS_UAO_UC_WR_OFFSET, + .info_bits = 0x20005001, + .refill = 0x00002524, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU7P5_IS_MMU_FW_WR_L1_BLOCKNR_REG, + .l2_block = IPU7P5_IS_MMU_FW_WR_L2_BLOCKNR_REG, + .nr_l1streams = IPU7P5_IS_MMU_FW_WR_STREAM_NUM, + .nr_l2streams = IPU7P5_IS_MMU_FW_WR_STREAM_NUM, + .l1_block_sz = { + 0x0, 0x8, 0xa, + }, + .l2_block_sz = { + 0x0, 0x2, 0x4, + }, + .zlx_nr = IPU7P5_IS_ZLX_UC_WR_NUM, + .zlx_axi_pool = { + 0x00000f20, + }, + .zlx_en = { + 0, 1, 1, 0, + }, + .zlx_conf = { + 0x0, + 0x00010101, + 0x00010101, + 0x0, + }, + .uao_p_num = IPU7P5_IS_UAO_UC_WR_PLANENUM, + .uao_p2tlb = { + 0x00000049, + 0x0000004a, + 0x0000004b, + 0x00000000, + }, + }, + { + .name = "IS_DATA_WR_ISOC", + .offset = IPU7P5_IS_MMU_M0_OFFSET, + .zlx_offset = IPU7P5_IS_ZLX_M0_OFFSET, + .uao_offset = IPU7P5_IS_UAO_M0_WR_OFFSET, + .info_bits = 0x20004e01, + .refill = 0x00002120, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU7P5_IS_MMU_M0_L1_BLOCKNR_REG, + .l2_block = IPU7P5_IS_MMU_M0_L2_BLOCKNR_REG, + .nr_l1streams = IPU7P5_IS_MMU_M0_STREAM_NUM, + .nr_l2streams = IPU7P5_IS_MMU_M0_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + }, + .zlx_nr = IPU7P5_IS_ZLX_M0_NUM, + .zlx_axi_pool = { + 0x00000f10, + }, + .zlx_en = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + }, + .zlx_conf = { + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + }, + .uao_p_num = IPU7P5_IS_UAO_M0_WR_PLANENUM, + .uao_p2tlb = { + 0x00000041, + 0x00000042, + 0x00000043, + 0x00000044, + 0x00000041, + 0x00000042, + 0x00000043, + 0x00000044, + 0x00000041, + 0x00000042, + 0x00000043, + 0x00000044, + 0x00000041, + 0x00000042, + 0x00000043, + 0x00000044, + }, + }, + { + .name = "IS_DATA_WR_SNOOP", + .offset = IPU7P5_IS_MMU_M1_OFFSET, + .zlx_offset = IPU7P5_IS_ZLX_M1_OFFSET, + .uao_offset = IPU7P5_IS_UAO_M1_WR_OFFSET, + .info_bits = 0x20004f01, + .refill = 0x00002322, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU7P5_IS_MMU_M1_L1_BLOCKNR_REG, + .l2_block = IPU7P5_IS_MMU_M1_L2_BLOCKNR_REG, + .nr_l1streams = IPU7P5_IS_MMU_M1_STREAM_NUM, + .nr_l2streams = IPU7P5_IS_MMU_M1_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + }, + .zlx_nr = IPU7P5_IS_ZLX_M1_NUM, + .zlx_axi_pool = { + 0x00000f20, + }, + .zlx_en = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + }, + .zlx_conf = { + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + }, + .uao_p_num = IPU7P5_IS_UAO_M1_WR_PLANENUM, + .uao_p2tlb = { + 0x00000045, + 0x00000046, + 0x00000047, + 0x00000048, + 0x00000045, + 0x00000046, + 0x00000047, + 0x00000048, + 0x00000045, + 0x00000046, + 0x00000047, + 0x00000048, + 0x00000045, + 0x00000046, + 0x00000047, + 0x00000048, + }, + }, + }, + .cdc_fifos = 3, + .cdc_fifo_threshold = {6, 8, 2}, + .dmem_offset = IPU_ISYS_DMEM_OFFSET, + .spc_offset = IPU_ISYS_SPC_OFFSET, + }, + .isys_dma_overshoot = IPU_ISYS_OVERALLOC_MIN, +}; + +static struct ipu_psys_internal_pdata ipu7p5_psys_ipdata = { + .hw_variant = { + .offset = IPU_UNIFIED_OFFSET, + .nr_mmus = IPU7P5_PS_MMU_NUM, + .mmu_hw = { + { + .name = "PS_FW_RD", + .offset = IPU7P5_PS_MMU_FW_RD_OFFSET, + .zlx_offset = IPU7P5_PS_ZLX_FW_RD_OFFSET, + .uao_offset = IPU7P5_PS_UAO_FW_RD_OFFSET, + .info_bits = 0x20004001, + .refill = 0x00002726, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU7P5_PS_MMU_FW_RD_L1_BLOCKNR_REG, + .l2_block = IPU7P5_PS_MMU_FW_RD_L2_BLOCKNR_REG, + .nr_l1streams = IPU7P5_PS_MMU_FW_RD_STREAM_NUM, + .nr_l2streams = IPU7P5_PS_MMU_FW_RD_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000d, + 0x0000000f, + 0x00000011, + 0x00000012, + 0x00000013, + 0x00000014, + 0x00000016, + 0x00000018, + 0x00000019, + 0x0000001a, + 0x0000001a, + 0x0000001a, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + }, + .zlx_nr = IPU7P5_PS_ZLX_FW_RD_NUM, + .zlx_axi_pool = { + 0x00000f30, + }, + .zlx_en = { + 0, 1, 0, 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, + }, + .zlx_conf = { + 0x00000000, + 0x00010101, + 0x00000000, + 0x00000000, + 0x00010101, + 0x00010101, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00010101, + 0x00010101, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + .uao_p_num = IPU7P5_PS_UAO_FW_RD_PLANENUM, + .uao_p2tlb = { + 0x0000002e, + 0x00000035, + 0x00000036, + 0x00000031, + 0x00000037, + 0x00000038, + 0x00000039, + 0x00000032, + 0x00000033, + 0x0000003a, + 0x0000003b, + 0x0000003c, + 0x00000034, + 0x0, + 0x0, + 0x0, + }, + }, + { + .name = "PS_FW_WR", + .offset = IPU7P5_PS_MMU_FW_WR_OFFSET, + .zlx_offset = IPU7P5_PS_ZLX_FW_WR_OFFSET, + .uao_offset = IPU7P5_PS_UAO_FW_WR_OFFSET, + .info_bits = 0x20003e01, + .refill = 0x00002322, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU7P5_PS_MMU_FW_WR_L1_BLOCKNR_REG, + .l2_block = IPU7P5_PS_MMU_FW_WR_L2_BLOCKNR_REG, + .nr_l1streams = IPU7P5_PS_MMU_FW_WR_STREAM_NUM, + .nr_l2streams = IPU7P5_PS_MMU_FW_WR_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000d, + 0x0000000e, + 0x0000000f, + 0x00000010, + 0x00000010, + 0x00000010, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + }, + .zlx_nr = IPU7P5_PS_ZLX_FW_WR_NUM, + .zlx_axi_pool = { + 0x00000f20, + }, + .zlx_en = { + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, + }, + .zlx_conf = { + 0x00000000, + 0x00010101, + 0x00010101, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + .uao_p_num = IPU7P5_PS_UAO_FW_WR_PLANENUM, + .uao_p2tlb = { + 0x0000002e, + 0x0000002f, + 0x00000030, + 0x00000031, + 0x00000032, + 0x00000033, + 0x00000034, + 0x0, + 0x0, + 0x0, + }, + }, + { + .name = "PS_DATA_RD", + .offset = IPU7P5_PS_MMU_SRT_RD_OFFSET, + .zlx_offset = IPU7P5_PS_ZLX_DATA_RD_OFFSET, + .uao_offset = IPU7P5_PS_UAO_SRT_RD_OFFSET, + .info_bits = 0x20003f01, + .refill = 0x00002524, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU7P5_PS_MMU_SRT_RD_L1_BLOCKNR_REG, + .l2_block = IPU7P5_PS_MMU_SRT_RD_L2_BLOCKNR_REG, + .nr_l1streams = IPU7P5_PS_MMU_SRT_RD_STREAM_NUM, + .nr_l2streams = IPU7P5_PS_MMU_SRT_RD_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000b, + 0x0000000d, + 0x0000000f, + 0x00000013, + 0x00000017, + 0x00000019, + 0x0000001b, + 0x0000001d, + 0x0000001f, + 0x0000002b, + 0x00000033, + 0x0000003f, + 0x00000047, + 0x00000049, + 0x0000004b, + 0x0000004c, + 0x0000004d, + 0x0000004e, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + 0x00000020, + 0x00000022, + 0x00000024, + 0x00000026, + 0x00000028, + 0x0000002a, + }, + .zlx_nr = IPU7P5_PS_ZLX_DATA_RD_NUM, + .zlx_axi_pool = { + 0x00000f30, + }, + .zlx_en = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, + }, + .zlx_conf = { + 0x00030303, + 0x00010101, + 0x00010101, + 0x00030202, + 0x00010101, + 0x00010101, + 0x00030303, + 0x00030303, + 0x00010101, + 0x00030800, + 0x00030500, + 0x00020101, + 0x00042000, + 0x00031000, + 0x00042000, + 0x00031000, + 0x00020400, + 0x00010101, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + .uao_p_num = IPU7P5_PS_UAO_SRT_RD_PLANENUM, + .uao_p2tlb = { + 0x0000001c, + 0x0000001d, + 0x0000001e, + 0x0000001f, + 0x00000020, + 0x00000021, + 0x00000022, + 0x00000023, + 0x00000024, + 0x00000025, + 0x00000026, + 0x00000027, + 0x00000028, + 0x00000029, + 0x0000002a, + 0x0000002b, + 0x0000002c, + 0x0000002d, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + }, + { + .name = "PS_DATA_WR", + .offset = IPU7P5_PS_MMU_SRT_WR_OFFSET, + .zlx_offset = IPU7P5_PS_ZLX_DATA_WR_OFFSET, + .uao_offset = IPU7P5_PS_UAO_SRT_WR_OFFSET, + .info_bits = 0x20003d01, + .refill = 0x00002120, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU7P5_PS_MMU_SRT_WR_L1_BLOCKNR_REG, + .l2_block = IPU7P5_PS_MMU_SRT_WR_L2_BLOCKNR_REG, + .nr_l1streams = IPU7P5_PS_MMU_SRT_WR_STREAM_NUM, + .nr_l2streams = IPU7P5_PS_MMU_SRT_WR_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000002, + 0x00000006, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + 0x00000020, + 0x00000022, + 0x00000024, + 0x00000028, + 0x0000002a, + 0x00000036, + 0x0000003e, + 0x00000040, + 0x00000042, + 0x0000004e, + 0x00000056, + 0x0000005c, + 0x00000068, + 0x00000070, + 0x00000076, + 0x00000077, + 0x00000078, + 0x00000079, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000006, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + 0x00000020, + 0x00000022, + 0x00000024, + 0x00000028, + 0x0000002a, + 0x00000036, + 0x0000003e, + 0x00000040, + 0x00000042, + 0x0000004e, + 0x00000056, + 0x0000005c, + 0x00000068, + 0x00000070, + 0x00000076, + 0x00000077, + 0x00000078, + 0x00000079, + }, + .zlx_nr = IPU7P5_PS_ZLX_DATA_WR_NUM, + .zlx_axi_pool = { + 0x00000f50, + }, + .zlx_en = { + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, + }, + .zlx_conf = { + 0x00010102, + 0x00030103, + 0x00030103, + 0x00010101, + 0x00010101, + 0x00030101, + 0x00010101, + 0x38010101, + 0x00000000, + 0x00000000, + 0x38010101, + 0x38010101, + 0x38010101, + 0x38010101, + 0x38010101, + 0x38010101, + 0x00030303, + 0x00010101, + 0x00042000, + 0x00031000, + 0x00010101, + 0x00010101, + 0x00042000, + 0x00031000, + 0x00031000, + 0x00042000, + 0x00031000, + 0x00031000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + .uao_p_num = IPU7P5_PS_UAO_SRT_WR_PLANENUM, + .uao_p2tlb = { + 0x00000000, + 0x00000001, + 0x00000002, + 0x00000003, + 0x00000004, + 0x00000005, + 0x00000006, + 0x00000007, + 0x00000008, + 0x00000009, + 0x0000000a, + 0x0000000b, + 0x0000000c, + 0x0000000d, + 0x0000000e, + 0x0000000f, + 0x00000010, + 0x00000011, + 0x00000012, + 0x00000013, + 0x00000014, + 0x00000015, + 0x00000016, + 0x00000017, + 0x00000018, + 0x00000019, + 0x0000001a, + 0x0000001b, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + }, + }, + }, + .dmem_offset = IPU_PSYS_DMEM_OFFSET, + }, +}; + +static struct ipu_isys_internal_pdata ipu7_isys_ipdata = { + .csi2 = { + .gpreg = IS_IO_CSI2_GPREGS_BASE, + }, + .hw_variant = { + .offset = IPU_UNIFIED_OFFSET, + .nr_mmus = IPU7_IS_MMU_NUM, + .mmu_hw = { + { + .name = "IS_FW_RD", + .offset = IPU7_IS_MMU_FW_RD_OFFSET, + .zlx_offset = IPU7_IS_ZLX_UC_RD_OFFSET, + .uao_offset = IPU7_IS_UAO_UC_RD_OFFSET, + .info_bits = 0x20006701, + .refill = 0x00002726, + .collapse_en_bitmap = 0x0, + .l1_block = IPU7_IS_MMU_FW_RD_L1_BLOCKNR_REG, + .l2_block = IPU7_IS_MMU_FW_RD_L2_BLOCKNR_REG, + .nr_l1streams = IPU7_IS_MMU_FW_RD_STREAM_NUM, + .nr_l2streams = IPU7_IS_MMU_FW_RD_STREAM_NUM, + .l1_block_sz = { + 0x0, 0x8, 0xa, + }, + .l2_block_sz = { + 0x0, 0x2, 0x4, + }, + .zlx_nr = IPU7_IS_ZLX_UC_RD_NUM, + .zlx_axi_pool = { + 0x00000f30, + }, + .zlx_en = { + 0, 0, 0, 0 + }, + .zlx_conf = { + 0x0, 0x0, 0x0, 0x0, + }, + .uao_p_num = IPU7_IS_UAO_UC_RD_PLANENUM, + .uao_p2tlb = { + 0x00000061, + 0x00000064, + 0x00000065, + }, + }, + { + .name = "IS_FW_WR", + .offset = IPU7_IS_MMU_FW_WR_OFFSET, + .zlx_offset = IPU7_IS_ZLX_UC_WR_OFFSET, + .uao_offset = IPU7_IS_UAO_UC_WR_OFFSET, + .info_bits = 0x20006801, + .refill = 0x00002524, + .collapse_en_bitmap = 0x0, + .l1_block = IPU7_IS_MMU_FW_WR_L1_BLOCKNR_REG, + .l2_block = IPU7_IS_MMU_FW_WR_L2_BLOCKNR_REG, + .nr_l1streams = IPU7_IS_MMU_FW_WR_STREAM_NUM, + .nr_l2streams = IPU7_IS_MMU_FW_WR_STREAM_NUM, + .l1_block_sz = { + 0x0, 0x8, 0xa, + }, + .l2_block_sz = { + 0x0, 0x2, 0x4, + }, + .zlx_nr = IPU7_IS_ZLX_UC_WR_NUM, + .zlx_axi_pool = { + 0x00000f20, + }, + .zlx_en = { + 0, 1, 1, 0, + }, + .zlx_conf = { + 0x0, + 0x00010101, + 0x00010101, + }, + .uao_p_num = IPU7_IS_UAO_UC_WR_PLANENUM, + .uao_p2tlb = { + 0x00000061, + 0x00000062, + 0x00000063, + }, + }, + { + .name = "IS_DATA_WR_ISOC", + .offset = IPU7_IS_MMU_M0_OFFSET, + .zlx_offset = IPU7_IS_ZLX_M0_OFFSET, + .uao_offset = IPU7_IS_UAO_M0_WR_OFFSET, + .info_bits = 0x20006601, + .refill = 0x00002120, + .collapse_en_bitmap = 0x0, + .l1_block = IPU7_IS_MMU_M0_L1_BLOCKNR_REG, + .l2_block = IPU7_IS_MMU_M0_L2_BLOCKNR_REG, + .nr_l1streams = IPU7_IS_MMU_M0_STREAM_NUM, + .nr_l2streams = IPU7_IS_MMU_M0_STREAM_NUM, + .l1_block_sz = { + 0x0, 0x3, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, + }, + .l2_block_sz = { + 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, + }, + .zlx_nr = IPU7_IS_ZLX_M0_NUM, + .zlx_axi_pool = { + 0x00000f10, + }, + .zlx_en = { + 1, 1, 1, 1, 1, 1, 1, 1, + }, + .zlx_conf = { + 0x00010103, + 0x00010103, + 0x00010101, + 0x00010101, + 0x00010101, + 0x00010101, + 0x00010101, + 0x00010101, + }, + .uao_p_num = IPU7_IS_UAO_M0_WR_PLANENUM, + .uao_p2tlb = { + 0x00000049, + 0x0000004a, + 0x0000004b, + 0x0000004c, + 0x0000004d, + 0x0000004e, + 0x0000004f, + 0x00000050, + }, + }, + { + .name = "IS_DATA_WR_SNOOP", + .offset = IPU7_IS_MMU_M1_OFFSET, + .zlx_offset = IPU7_IS_ZLX_M1_OFFSET, + .uao_offset = IPU7_IS_UAO_M1_WR_OFFSET, + .info_bits = 0x20006901, + .refill = 0x00002322, + .collapse_en_bitmap = 0x0, + .l1_block = IPU7_IS_MMU_M1_L1_BLOCKNR_REG, + .l2_block = IPU7_IS_MMU_M1_L2_BLOCKNR_REG, + .nr_l1streams = IPU7_IS_MMU_M1_STREAM_NUM, + .nr_l2streams = IPU7_IS_MMU_M1_STREAM_NUM, + .l1_block_sz = { + 0x0, 0x3, 0x6, 0x9, 0xc, + 0xe, 0x10, 0x12, 0x14, 0x16, + 0x18, 0x1a, 0x1c, 0x1e, 0x20, + 0x22, + }, + .l2_block_sz = { + 0x0, 0x2, 0x4, 0x6, 0x8, + 0xa, 0xc, 0xe, 0x10, 0x12, + 0x14, 0x16, 0x18, 0x1a, 0x1c, + 0x1e, + }, + .zlx_nr = IPU7_IS_ZLX_M1_NUM, + .zlx_axi_pool = { + 0x00000f20, + }, + .zlx_en = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + }, + .zlx_conf = { + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010103, + 0x00010101, + 0x00010101, + 0x00010101, + 0x00010101, + 0x00010101, + 0x00010101, + 0x00010101, + 0x00010101, + }, + .uao_p_num = IPU7_IS_UAO_M1_WR_PLANENUM, + .uao_p2tlb = { + 0x00000051, + 0x00000052, + 0x00000053, + 0x00000054, + 0x00000055, + 0x00000056, + 0x00000057, + 0x00000058, + 0x00000059, + 0x0000005a, + 0x0000005b, + 0x0000005c, + 0x0000005d, + 0x0000005e, + 0x0000005f, + 0x00000060, + }, + }, + }, + .cdc_fifos = 3, + .cdc_fifo_threshold = {6, 8, 2}, + .dmem_offset = IPU_ISYS_DMEM_OFFSET, + .spc_offset = IPU_ISYS_SPC_OFFSET, + }, + .isys_dma_overshoot = IPU_ISYS_OVERALLOC_MIN, +}; + +static struct ipu_psys_internal_pdata ipu7_psys_ipdata = { + .hw_variant = { + .offset = IPU_UNIFIED_OFFSET, + .nr_mmus = IPU7_PS_MMU_NUM, + .mmu_hw = { + { + .name = "PS_FW_RD", + .offset = IPU7_PS_MMU_FW_RD_OFFSET, + .zlx_offset = IPU7_PS_ZLX_FW_RD_OFFSET, + .uao_offset = IPU7_PS_UAO_FW_RD_OFFSET, + .info_bits = 0x20004801, + .refill = 0x00002726, + .collapse_en_bitmap = 0x0, + .l1_block = IPU7_PS_MMU_FW_RD_L1_BLOCKNR_REG, + .l2_block = IPU7_PS_MMU_FW_RD_L2_BLOCKNR_REG, + .nr_l1streams = IPU7_PS_MMU_FW_RD_STREAM_NUM, + .nr_l2streams = IPU7_PS_MMU_FW_RD_STREAM_NUM, + .l1_block_sz = { + 0, 0x8, 0xa, 0xc, 0xd, + 0xf, 0x11, 0x12, 0x13, 0x14, + 0x16, 0x18, 0x19, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + }, + .l2_block_sz = { + 0x0, 0x2, 0x4, 0x6, 0x8, + 0xa, 0xc, 0xe, 0x10, 0x12, + 0x14, 0x16, 0x18, 0x1a, 0x1c, + 0x1e, 0x20, 0x22, 0x24, 0x26, + }, + .zlx_nr = IPU7_PS_ZLX_FW_RD_NUM, + .zlx_axi_pool = { + 0x00000f30, + }, + .zlx_en = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }, + .zlx_conf = { + 0x0, + }, + .uao_p_num = IPU7_PS_UAO_FW_RD_PLANENUM, + .uao_p2tlb = { + 0x00000036, + 0x0000003d, + 0x0000003e, + 0x00000039, + 0x0000003f, + 0x00000040, + 0x00000041, + 0x0000003a, + 0x0000003b, + 0x00000042, + 0x00000043, + 0x00000044, + 0x0000003c, + }, + }, + { + .name = "PS_FW_WR", + .offset = IPU7_PS_MMU_FW_WR_OFFSET, + .zlx_offset = IPU7_PS_ZLX_FW_WR_OFFSET, + .uao_offset = IPU7_PS_UAO_FW_WR_OFFSET, + .info_bits = 0x20004601, + .refill = 0x00002322, + .collapse_en_bitmap = 0x0, + .l1_block = IPU7_PS_MMU_FW_WR_L1_BLOCKNR_REG, + .l2_block = IPU7_PS_MMU_FW_WR_L2_BLOCKNR_REG, + .nr_l1streams = IPU7_PS_MMU_FW_WR_STREAM_NUM, + .nr_l2streams = IPU7_PS_MMU_FW_WR_STREAM_NUM, + .l1_block_sz = { + 0, 0x8, 0xa, 0xc, 0xd, + 0xe, 0xf, 0x10, 0x10, 0x10, + }, + .l2_block_sz = { + 0x0, 0x2, 0x4, 0x6, 0x8, + 0xa, 0xc, 0xe, 0x10, 0x12, + }, + .zlx_nr = IPU7_PS_ZLX_FW_WR_NUM, + .zlx_axi_pool = { + 0x00000f20, + }, + .zlx_en = { + 0, 1, 1, 0, 0, 0, 0, 0, + 0, 0, + }, + .zlx_conf = { + 0x0, + 0x00010101, + 0x00010101, + }, + .uao_p_num = IPU7_PS_UAO_FW_WR_PLANENUM, + .uao_p2tlb = { + 0x00000036, + 0x00000037, + 0x00000038, + 0x00000039, + 0x0000003a, + 0x0000003b, + 0x0000003c, + }, + }, + { + .name = "PS_DATA_RD", + .offset = IPU7_PS_MMU_SRT_RD_OFFSET, + .zlx_offset = IPU7_PS_ZLX_DATA_RD_OFFSET, + .uao_offset = IPU7_PS_UAO_SRT_RD_OFFSET, + .info_bits = 0x20004701, + .refill = 0x00002120, + .collapse_en_bitmap = 0x0, + .l1_block = IPU7_PS_MMU_SRT_RD_L1_BLOCKNR_REG, + .l2_block = IPU7_PS_MMU_SRT_RD_L2_BLOCKNR_REG, + .nr_l1streams = IPU7_PS_MMU_SRT_RD_STREAM_NUM, + .nr_l2streams = IPU7_PS_MMU_SRT_RD_STREAM_NUM, + .l1_block_sz = { + 0x0, 0x4, 0x6, 0x8, 0xb, + 0xd, 0xf, 0x11, 0x13, 0x15, + 0x17, 0x23, 0x2b, 0x37, 0x3f, + 0x41, 0x43, 0x44, 0x45, 0x46, + 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x53, 0x55, 0x57, + 0x59, 0x5b, 0x5d, 0x5f, 0x61, + }, + .l2_block_sz = { + 0x0, 0x2, 0x4, 0x6, 0x8, + 0xa, 0xc, 0xe, 0x10, 0x12, + 0x14, 0x16, 0x18, 0x1a, 0x1c, + 0x1e, 0x20, 0x22, 0x24, 0x26, + 0x28, 0x2a, 0x2c, 0x2e, 0x30, + 0x32, 0x34, 0x36, 0x38, 0x3a, + 0x3c, 0x3e, 0x40, 0x42, 0x44, + 0x46, 0x48, 0x4a, 0x4c, 0x4e, + }, + .zlx_nr = IPU7_PS_ZLX_DATA_RD_NUM, + .zlx_axi_pool = { + 0x00000f30, + }, + .zlx_en = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }, + .zlx_conf = { + 0x00030303, + 0x00010101, + 0x00010101, + 0x00030202, + 0x00010101, + 0x00010101, + 0x00010101, + 0x00030800, + 0x00030500, + 0x00020101, + 0x00042000, + 0x00031000, + 0x00042000, + 0x00031000, + 0x00020400, + 0x00010101, + }, + .uao_p_num = IPU7_PS_UAO_SRT_RD_PLANENUM, + .uao_p2tlb = { + 0x00000022, + 0x00000023, + 0x00000024, + 0x00000025, + 0x00000026, + 0x00000027, + 0x00000028, + 0x00000029, + 0x0000002a, + 0x0000002b, + 0x0000002c, + 0x0000002d, + 0x0000002e, + 0x0000002f, + 0x00000030, + 0x00000031, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0000001e, + 0x0000001f, + 0x00000020, + 0x00000021, + 0x00000032, + 0x00000033, + 0x00000034, + 0x00000035, + }, + }, + { + .name = "PS_DATA_WR", + .offset = IPU7_PS_MMU_SRT_WR_OFFSET, + .zlx_offset = IPU7_PS_ZLX_DATA_WR_OFFSET, + .uao_offset = IPU7_PS_UAO_SRT_WR_OFFSET, + .info_bits = 0x20004501, + .refill = 0x00002120, + .collapse_en_bitmap = 0x0, + .l1_block = IPU7_PS_MMU_SRT_WR_L1_BLOCKNR_REG, + .l2_block = IPU7_PS_MMU_SRT_WR_L2_BLOCKNR_REG, + .nr_l1streams = IPU7_PS_MMU_SRT_WR_STREAM_NUM, + .nr_l2streams = IPU7_PS_MMU_SRT_WR_STREAM_NUM, + .l1_block_sz = { + 0x0, 0x2, 0x6, 0xa, 0xc, + 0xe, 0x10, 0x12, 0x14, 0x16, + 0x18, 0x1a, 0x1c, 0x1e, 0x20, + 0x22, 0x24, 0x26, 0x32, 0x3a, + 0x3c, 0x3e, 0x4a, 0x52, 0x58, + 0x64, 0x6c, 0x72, 0x7e, 0x86, + 0x8c, 0x8d, 0x8e, 0x8f, 0x90, + 0x91, 0x92, 0x94, 0x96, 0x98, + }, + .l2_block_sz = { + 0x0, 0x2, 0x4, 0x6, 0x8, + 0xa, 0xc, 0xe, 0x10, 0x12, + 0x14, 0x16, 0x18, 0x1a, 0x1c, + 0x1e, 0x20, 0x22, 0x24, 0x26, + 0x28, 0x2a, 0x2c, 0x2e, 0x30, + 0x32, 0x34, 0x36, 0x38, 0x3a, + 0x3c, 0x3e, 0x40, 0x42, 0x44, + 0x46, 0x48, 0x4a, 0x4c, 0x4e, + }, + .zlx_nr = IPU7_PS_ZLX_DATA_WR_NUM, + .zlx_axi_pool = { + 0x00000f50, + }, + .zlx_en = { + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, + }, + .zlx_conf = { + 0x00010102, + 0x00030103, + 0x00030103, + 0x00010101, + 0x00010101, + 0x00030101, + 0x00010101, + 0x38010101, + 0x0, + 0x0, + 0x38010101, + 0x38010101, + 0x38010101, + 0x38010101, + 0x38010101, + 0x38010101, + 0x00010101, + 0x00042000, + 0x00031000, + 0x00010101, + 0x00010101, + 0x00042000, + 0x00031000, + 0x00031000, + 0x00042000, + 0x00031000, + 0x00031000, + 0x00042000, + 0x00031000, + 0x00031000, + 0x0, + 0x0, + }, + .uao_p_num = IPU7_PS_UAO_SRT_WR_PLANENUM, + .uao_p2tlb = { + 0x00000000, + 0x00000001, + 0x00000002, + 0x00000003, + 0x00000004, + 0x00000005, + 0x00000006, + 0x00000007, + 0x00000008, + 0x00000009, + 0x0000000a, + 0x0000000b, + 0x0000000c, + 0x0000000d, + 0x0000000e, + 0x0000000f, + 0x00000010, + 0x00000011, + 0x00000012, + 0x00000013, + 0x00000014, + 0x00000015, + 0x00000016, + 0x00000017, + 0x00000018, + 0x00000019, + 0x0000001a, + 0x0000001b, + 0x0000001c, + 0x0000001d, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0000001e, + 0x0000001f, + 0x00000020, + 0x00000021, + }, + }, + }, + .dmem_offset = IPU_PSYS_DMEM_OFFSET, + }, +}; + +static struct ipu_isys_internal_pdata ipu8_isys_ipdata = { + .csi2 = { + .gpreg = IPU8_IS_IO_CSI2_GPREGS_BASE, + }, + .hw_variant = { + .offset = IPU_UNIFIED_OFFSET, + .nr_mmus = IPU8_IS_MMU_NUM, + .mmu_hw = { + { + .name = "IS_FW_RD", + .offset = IPU8_IS_MMU_FW_RD_OFFSET, + .zlx_offset = IPU8_IS_ZLX_UC_RD_OFFSET, + .uao_offset = IPU8_IS_UAO_UC_RD_OFFSET, + .info_bits = 0x20005101, + .refill = 0x00002726, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU8_IS_MMU_FW_RD_L1_BLOCKNR_REG, + .l2_block = IPU8_IS_MMU_FW_RD_L2_BLOCKNR_REG, + .nr_l1streams = IPU8_IS_MMU_FW_RD_STREAM_NUM, + .nr_l2streams = IPU8_IS_MMU_FW_RD_STREAM_NUM, + .l1_block_sz = { + 0x0, 0x8, 0xa, + }, + .l2_block_sz = { + 0x0, 0x2, 0x4, + }, + .zlx_nr = IPU8_IS_ZLX_UC_RD_NUM, + .zlx_axi_pool = { + 0x00000f30, + }, + .zlx_en = { + 0, 1, 0, 0 + }, + .zlx_conf = { + 0, 2, 0, 0 + }, + .uao_p_num = IPU8_IS_UAO_UC_RD_PLANENUM, + .uao_p2tlb = { + 0x00000049, + 0x0000004c, + 0x0000004d, + 0x00000000, + }, + }, + { + .name = "IS_FW_WR", + .offset = IPU8_IS_MMU_FW_WR_OFFSET, + .zlx_offset = IPU8_IS_ZLX_UC_WR_OFFSET, + .uao_offset = IPU8_IS_UAO_UC_WR_OFFSET, + .info_bits = 0x20005001, + .refill = 0x00002524, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU8_IS_MMU_FW_WR_L1_BLOCKNR_REG, + .l2_block = IPU8_IS_MMU_FW_WR_L2_BLOCKNR_REG, + .nr_l1streams = IPU8_IS_MMU_FW_WR_STREAM_NUM, + .nr_l2streams = IPU8_IS_MMU_FW_WR_STREAM_NUM, + .l1_block_sz = { + 0x0, 0x8, 0xa, + }, + .l2_block_sz = { + 0x0, 0x2, 0x4, + }, + .zlx_nr = IPU8_IS_ZLX_UC_WR_NUM, + .zlx_axi_pool = { + 0x00000f20, + }, + .zlx_en = { + 0, 1, 1, 0, + }, + .zlx_conf = { + 0x0, + 0x2, + 0x2, + 0x0, + }, + .uao_p_num = IPU8_IS_UAO_UC_WR_PLANENUM, + .uao_p2tlb = { + 0x00000049, + 0x0000004a, + 0x0000004b, + 0x00000000, + }, + }, + { + .name = "IS_DATA_WR_ISOC", + .offset = IPU8_IS_MMU_M0_OFFSET, + .zlx_offset = IPU8_IS_ZLX_M0_OFFSET, + .uao_offset = IPU8_IS_UAO_M0_WR_OFFSET, + .info_bits = 0x20004e01, + .refill = 0x00002120, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU8_IS_MMU_M0_L1_BLOCKNR_REG, + .l2_block = IPU8_IS_MMU_M0_L2_BLOCKNR_REG, + .nr_l1streams = IPU8_IS_MMU_M0_STREAM_NUM, + .nr_l2streams = IPU8_IS_MMU_M0_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + }, + .zlx_nr = IPU8_IS_ZLX_M0_NUM, + .zlx_axi_pool = { + 0x00000f10, + }, + .zlx_en = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + }, + .zlx_conf = { + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + }, + .uao_p_num = IPU8_IS_UAO_M0_WR_PLANENUM, + .uao_p2tlb = { + 0x0000003b, + 0x0000003c, + 0x0000003d, + 0x0000003e, + 0x0000003b, + 0x0000003c, + 0x0000003d, + 0x0000003e, + 0x0000003b, + 0x0000003c, + 0x0000003d, + 0x0000003e, + 0x0000003b, + 0x0000003c, + 0x0000003d, + 0x0000003e, + }, + }, + { + .name = "IS_DATA_WR_SNOOP", + .offset = IPU8_IS_MMU_M1_OFFSET, + .zlx_offset = IPU8_IS_ZLX_M1_OFFSET, + .uao_offset = IPU8_IS_UAO_M1_WR_OFFSET, + .info_bits = 0x20004f01, + .refill = 0x00002322, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU8_IS_MMU_M1_L1_BLOCKNR_REG, + .l2_block = IPU8_IS_MMU_M1_L2_BLOCKNR_REG, + .nr_l1streams = IPU8_IS_MMU_M1_STREAM_NUM, + .nr_l2streams = IPU8_IS_MMU_M1_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + }, + .zlx_nr = IPU8_IS_ZLX_M1_NUM, + .zlx_axi_pool = { + 0x00000f20, + }, + .zlx_en = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + }, + .zlx_conf = { + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + }, + .uao_p_num = IPU8_IS_UAO_M1_WR_PLANENUM, + .uao_p2tlb = { + 0x0000003f, + 0x00000040, + 0x00000041, + 0x00000042, + 0x0000003f, + 0x00000040, + 0x00000041, + 0x00000042, + 0x0000003f, + 0x00000040, + 0x00000041, + 0x00000042, + 0x0000003f, + 0x00000040, + 0x00000041, + 0x00000042, + }, + }, + { + .name = "IS_UPIPE", + .offset = IPU8_IS_MMU_UPIPE_OFFSET, + .zlx_offset = IPU8_IS_ZLX_UPIPE_OFFSET, + .uao_offset = IPU8_IS_UAO_UPIPE_OFFSET, + .info_bits = 0x20005201, + .refill = 0x00002928, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU8_IS_MMU_UPIPE_L1_BLOCKNR_REG, + .l2_block = IPU8_IS_MMU_UPIPE_L2_BLOCKNR_REG, + .nr_l1streams = IPU8_IS_MMU_UPIPE_STREAM_NUM, + .nr_l2streams = IPU8_IS_MMU_UPIPE_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + }, + .zlx_nr = IPU8_IS_ZLX_UPIPE_NUM, + .zlx_axi_pool = { + 0x00000f20, + }, + .zlx_en = { + 1, 1, 1, 1, 1, 1, + }, + .zlx_conf = { + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + 0x3, + }, + .uao_p_num = IPU8_IS_UAO_UPIPE_PLANENUM, + .uao_p2tlb = { + 0x00000043, + 0x00000044, + 0x00000045, + 0x00000046, + 0x00000047, + 0x00000048, + }, + }, + }, + .cdc_fifos = 3, + .cdc_fifo_threshold = {6, 8, 2}, + .dmem_offset = IPU_ISYS_DMEM_OFFSET, + .spc_offset = IPU_ISYS_SPC_OFFSET, + }, + .isys_dma_overshoot = IPU_ISYS_OVERALLOC_MIN, +}; + +static struct ipu_psys_internal_pdata ipu8_psys_ipdata = { + .hw_variant = { + .offset = IPU_UNIFIED_OFFSET, + .nr_mmus = IPU8_PS_MMU_NUM, + .mmu_hw = { + { + .name = "PS_FW_RD", + .offset = IPU8_PS_MMU_FW_RD_OFFSET, + .zlx_offset = IPU8_PS_ZLX_FW_RD_OFFSET, + .uao_offset = IPU8_PS_UAO_FW_RD_OFFSET, + .info_bits = 0x20003a01, + .refill = 0x00002726, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU8_PS_MMU_FW_RD_L1_BLOCKNR_REG, + .l2_block = IPU8_PS_MMU_FW_RD_L2_BLOCKNR_REG, + .nr_l1streams = IPU8_PS_MMU_FW_RD_STREAM_NUM, + .nr_l2streams = IPU8_PS_MMU_FW_RD_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000008, + 0x0000000a, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x00000018, + 0x00000018, + 0x00000018, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + }, + .zlx_nr = IPU8_PS_ZLX_FW_RD_NUM, + .zlx_axi_pool = { + 0x00000f30, + }, + .zlx_en = { + 0, 1, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, + }, + .zlx_conf = { + 0x0, + 0x2, + 0x0, + 0x0, + 0x2, + 0x2, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + }, + .uao_p_num = IPU8_PS_UAO_FW_RD_PLANENUM, + .uao_p2tlb = { + 0x0000002d, + 0x00000032, + 0x00000033, + 0x00000030, + 0x00000034, + 0x00000035, + 0x00000036, + 0x00000031, + 0x0, + 0x0, + 0x0, + 0x0, + }, + }, + { + .name = "PS_FW_WR", + .offset = IPU8_PS_MMU_FW_WR_OFFSET, + .zlx_offset = IPU8_PS_ZLX_FW_WR_OFFSET, + .uao_offset = IPU8_PS_UAO_FW_WR_OFFSET, + .info_bits = 0x20003901, + .refill = 0x00002524, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU8_PS_MMU_FW_WR_L1_BLOCKNR_REG, + .l2_block = IPU8_PS_MMU_FW_WR_L2_BLOCKNR_REG, + .nr_l1streams = IPU8_PS_MMU_FW_WR_STREAM_NUM, + .nr_l2streams = IPU8_PS_MMU_FW_WR_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000010, + 0x00000010, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + }, + .zlx_nr = IPU8_PS_ZLX_FW_WR_NUM, + .zlx_axi_pool = { + 0x00000f20, + }, + .zlx_en = { + 0, 1, 1, 0, 0, 0, 0, 0, + }, + .zlx_conf = { + 0x0, 0x2, 0x2, 0x0, + 0x0, 0x0, 0x0, 0x0, + }, + .uao_p_num = IPU8_PS_UAO_FW_WR_PLANENUM, + .uao_p2tlb = { + 0x0000002d, + 0x0000002e, + 0x0000002f, + 0x00000030, + 0x00000031, + 0x0, + 0x0, + 0x0, + }, + }, + { + .name = "PS_DATA_RD", + .offset = IPU8_PS_MMU_SRT_RD_OFFSET, + .zlx_offset = IPU8_PS_ZLX_DATA_RD_OFFSET, + .uao_offset = IPU8_PS_UAO_SRT_RD_OFFSET, + .info_bits = 0x20003801, + .refill = 0x00002322, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU8_PS_MMU_SRT_RD_L1_BLOCKNR_REG, + .l2_block = IPU8_PS_MMU_SRT_RD_L2_BLOCKNR_REG, + .nr_l1streams = IPU8_PS_MMU_SRT_RD_STREAM_NUM, + .nr_l2streams = IPU8_PS_MMU_SRT_RD_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000014, + 0x00000018, + 0x0000001c, + 0x0000001e, + 0x00000022, + 0x00000024, + 0x00000026, + 0x00000028, + 0x0000002a, + 0x0000002c, + 0x0000002e, + 0x00000030, + 0x00000032, + 0x00000036, + 0x0000003a, + 0x0000003c, + 0x0000003c, + 0x0000003c, + 0x0000003c, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + 0x00000020, + 0x00000022, + 0x00000024, + 0x00000026, + 0x00000028, + 0x0000002a, + 0x0000002c, + 0x0000002e, + 0x00000030, + 0x00000032, + }, + .zlx_nr = IPU8_PS_ZLX_DATA_RD_NUM, + .zlx_axi_pool = { + 0x00000f30, + }, + .zlx_en = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, + }, + .zlx_conf = { + 0x6, 0x3, 0x3, 0x6, + 0x2, 0x2, 0x6, 0x6, + 0x6, 0x3, 0x6, 0x3, + 0x3, 0x2, 0x2, 0x2, + 0x2, 0x2, 0x2, 0x6, + 0x6, 0x3, 0x0, 0x0, + 0x0, 0x0, + }, + .uao_p_num = IPU8_PS_UAO_SRT_RD_PLANENUM, + .uao_p2tlb = { + 0x00000017, + 0x00000018, + 0x00000019, + 0x0000001a, + 0x0000001b, + 0x0000001c, + 0x0000001d, + 0x0000001e, + 0x0000001f, + 0x00000020, + 0x00000021, + 0x00000022, + 0x00000023, + 0x00000024, + 0x00000025, + 0x00000026, + 0x00000027, + 0x00000028, + 0x00000029, + 0x0000002a, + 0x0000002b, + 0x0000002c, + 0x0, + 0x0, + 0x0, + 0x0, + }, + }, + { + .name = "PS_DATA_WR", + .offset = IPU8_PS_MMU_SRT_WR_OFFSET, + .zlx_offset = IPU8_PS_ZLX_DATA_WR_OFFSET, + .uao_offset = IPU8_PS_UAO_SRT_WR_OFFSET, + .info_bits = 0x20003701, + .refill = 0x00002120, + .collapse_en_bitmap = 0x1, + .at_sp_arb_cfg = 0x1, + .l1_block = IPU8_PS_MMU_SRT_WR_L1_BLOCKNR_REG, + .l2_block = IPU8_PS_MMU_SRT_WR_L2_BLOCKNR_REG, + .nr_l1streams = IPU8_PS_MMU_SRT_WR_STREAM_NUM, + .nr_l2streams = IPU8_PS_MMU_SRT_WR_STREAM_NUM, + .l1_block_sz = { + 0x00000000, + 0x00000002, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001c, + 0x0000001e, + 0x00000022, + 0x00000024, + 0x00000028, + 0x0000002a, + 0x0000002e, + 0x00000030, + 0x00000032, + 0x00000036, + 0x00000038, + 0x0000003a, + 0x0000003a, + 0x0000003a, + }, + .l2_block_sz = { + 0x00000000, + 0x00000002, + 0x00000004, + 0x00000006, + 0x00000008, + 0x0000000a, + 0x0000000c, + 0x0000000e, + 0x00000010, + 0x00000012, + 0x00000014, + 0x00000016, + 0x00000018, + 0x0000001a, + 0x0000001c, + 0x0000001e, + 0x00000020, + 0x00000022, + 0x00000024, + 0x00000026, + 0x00000028, + 0x0000002a, + 0x0000002c, + 0x0000002e, + 0x00000030, + 0x00000032, + }, + .zlx_nr = IPU8_PS_ZLX_DATA_WR_NUM, + .zlx_axi_pool = { + 0x00000f50, + }, + .zlx_en = { + 1, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, + }, + .zlx_conf = { + 0x3, + 0x6, + 0x38000002, + 0x38000000, + 0x3, + 0x38000002, + 0x38000002, + 0x38000002, + 0x38000002, + 0x38000002, + 0x38000002, + 0x6, + 0x3, + 0x6, + 0x3, + 0x6, + 0x3, + 0x6, + 0x3, + 0x3, + 0x6, + 0x3, + 0x3, + 0x0, + 0x0, + 0x0, + }, + .uao_p_num = IPU8_PS_UAO_SRT_WR_PLANENUM, + .uao_p2tlb = { + 0x00000000, + 0x00000001, + 0x00000002, + 0x00000003, + 0x00000004, + 0x00000005, + 0x00000006, + 0x00000007, + 0x00000008, + 0x00000009, + 0x0000000a, + 0x0000000b, + 0x0000000c, + 0x0000000d, + 0x0000000e, + 0x0000000f, + 0x00000010, + 0x00000011, + 0x00000012, + 0x00000013, + 0x00000014, + 0x00000015, + 0x00000016, + 0x00000000, + 0x00000000, + 0x00000000, + }, + }, + }, + .dmem_offset = IPU_PSYS_DMEM_OFFSET, + }, +}; + +static const struct ipu_buttress_ctrl ipu7_isys_buttress_ctrl = { + .subsys_id = IPU_IS, + .ratio = IPU7_IS_FREQ_CTL_DEFAULT_RATIO, + .ratio_shift = IPU_FREQ_CTL_RATIO_SHIFT, + .cdyn = IPU_FREQ_CTL_CDYN, + .cdyn_shift = IPU_FREQ_CTL_CDYN_SHIFT, + .freq_ctl = BUTTRESS_REG_IS_WORKPOINT_REQ, + .pwr_sts_shift = IPU_BUTTRESS_PWR_STATE_IS_PWR_SHIFT, + .pwr_sts_mask = IPU_BUTTRESS_PWR_STATE_IS_PWR_MASK, + .pwr_sts_on = IPU_BUTTRESS_PWR_STATE_UP_DONE, + .pwr_sts_off = IPU_BUTTRESS_PWR_STATE_DN_DONE, + .ovrd_clk = BUTTRESS_OVERRIDE_IS_CLK, + .own_clk_ack = BUTTRESS_OWN_ACK_IS_CLK, +}; + +static const struct ipu_buttress_ctrl ipu7_psys_buttress_ctrl = { + .subsys_id = IPU_PS, + .ratio = IPU7_PS_FREQ_CTL_DEFAULT_RATIO, + .ratio_shift = IPU_FREQ_CTL_RATIO_SHIFT, + .cdyn = IPU_FREQ_CTL_CDYN, + .cdyn_shift = IPU_FREQ_CTL_CDYN_SHIFT, + .freq_ctl = BUTTRESS_REG_PS_WORKPOINT_REQ, + .pwr_sts_shift = IPU_BUTTRESS_PWR_STATE_PS_PWR_SHIFT, + .pwr_sts_mask = IPU_BUTTRESS_PWR_STATE_PS_PWR_MASK, + .pwr_sts_on = IPU_BUTTRESS_PWR_STATE_UP_DONE, + .pwr_sts_off = IPU_BUTTRESS_PWR_STATE_DN_DONE, + .ovrd_clk = BUTTRESS_OVERRIDE_PS_CLK, + .own_clk_ack = BUTTRESS_OWN_ACK_PS_CLK, +}; + +static const struct ipu_buttress_ctrl ipu8_isys_buttress_ctrl = { + .subsys_id = IPU_IS, + .ratio = IPU8_IS_FREQ_CTL_DEFAULT_RATIO, + .ratio_shift = IPU_FREQ_CTL_RATIO_SHIFT, + .cdyn = IPU_FREQ_CTL_CDYN, + .cdyn_shift = IPU_FREQ_CTL_CDYN_SHIFT, + .freq_ctl = BUTTRESS_REG_IS_WORKPOINT_REQ, + .pwr_sts_shift = IPU_BUTTRESS_PWR_STATE_IS_PWR_SHIFT, + .pwr_sts_mask = IPU_BUTTRESS_PWR_STATE_IS_PWR_MASK, + .pwr_sts_on = IPU_BUTTRESS_PWR_STATE_UP_DONE, + .pwr_sts_off = IPU_BUTTRESS_PWR_STATE_DN_DONE, +}; + +static const struct ipu_buttress_ctrl ipu8_psys_buttress_ctrl = { + .subsys_id = IPU_PS, + .ratio = IPU8_PS_FREQ_CTL_DEFAULT_RATIO, + .ratio_shift = IPU_FREQ_CTL_RATIO_SHIFT, + .cdyn = IPU_FREQ_CTL_CDYN, + .cdyn_shift = IPU_FREQ_CTL_CDYN_SHIFT, + .freq_ctl = BUTTRESS_REG_PS_WORKPOINT_REQ, + .pwr_sts_shift = IPU_BUTTRESS_PWR_STATE_PS_PWR_SHIFT, + .pwr_sts_mask = IPU_BUTTRESS_PWR_STATE_PS_PWR_MASK, + .pwr_sts_on = IPU_BUTTRESS_PWR_STATE_UP_DONE, + .pwr_sts_off = IPU_BUTTRESS_PWR_STATE_DN_DONE, + .own_clk_ack = BUTTRESS_OWN_ACK_PS_PLL, +}; + +void ipu_internal_pdata_init(struct ipu_isys_internal_pdata *isys_ipdata, + struct ipu_psys_internal_pdata *psys_ipdata) +{ + isys_ipdata->csi2.nports = ARRAY_SIZE(ipu7_csi_offsets); + isys_ipdata->csi2.offsets = ipu7_csi_offsets; + isys_ipdata->num_parallel_streams = IPU7_ISYS_NUM_STREAMS; + psys_ipdata->hw_variant.spc_offset = IPU7_PSYS_SPC_OFFSET; +} + +static int ipu7_isys_check_fwnode_graph(struct fwnode_handle *fwnode) +{ + struct fwnode_handle *endpoint; + + if (IS_ERR_OR_NULL(fwnode)) + return -EINVAL; + + endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (endpoint) { + fwnode_handle_put(endpoint); + return 0; + } + + return ipu7_isys_check_fwnode_graph(fwnode->secondary); +} + +static struct ipu7_bus_device * +ipu7_isys_init(struct pci_dev *pdev, struct device *parent, + const struct ipu_buttress_ctrl *ctrl, void __iomem *base, + const struct ipu_isys_internal_pdata *ipdata, + unsigned int nr) +{ + struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev); + struct ipu7_bus_device *isys_adev; + struct device *dev = &pdev->dev; + struct ipu7_isys_pdata *pdata; + int ret; + + ret = ipu7_isys_check_fwnode_graph(fwnode); + if (ret) { + if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary)) { + dev_err(dev, + "fwnode graph has no endpoints connection\n"); + return ERR_PTR(-EINVAL); + } + + ret = ipu_bridge_init(dev, ipu_bridge_parse_ssdb); + if (ret) { + dev_err_probe(dev, ret, "IPU bridge init failed\n"); + return ERR_PTR(ret); + } + } + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->base = base; + pdata->ipdata = ipdata; + + isys_adev = ipu7_bus_initialize_device(pdev, parent, pdata, ctrl, + IPU_ISYS_NAME); + if (IS_ERR(isys_adev)) { + dev_err_probe(dev, PTR_ERR(isys_adev), + "ipu7_bus_initialize_device isys failed\n"); + kfree(pdata); + return ERR_CAST(isys_adev); + } + + isys_adev->mmu = ipu7_mmu_init(dev, base, ISYS_MMID, + &ipdata->hw_variant); + if (IS_ERR(isys_adev->mmu)) { + dev_err_probe(dev, PTR_ERR(isys_adev->mmu), + "ipu7_mmu_init(isys_adev->mmu) failed\n"); + put_device(&isys_adev->auxdev.dev); + kfree(pdata); + return ERR_CAST(isys_adev->mmu); + } + + isys_adev->mmu->dev = &isys_adev->auxdev.dev; + isys_adev->subsys = IPU_IS; + + ret = ipu7_bus_add_device(isys_adev); + if (ret) { + kfree(pdata); + return ERR_PTR(ret); + } + + return isys_adev; +} + +static struct ipu7_bus_device * +ipu7_psys_init(struct pci_dev *pdev, struct device *parent, + const struct ipu_buttress_ctrl *ctrl, void __iomem *base, + const struct ipu_psys_internal_pdata *ipdata, unsigned int nr) +{ + struct ipu7_bus_device *psys_adev; + struct ipu7_psys_pdata *pdata; + int ret; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->base = base; + pdata->ipdata = ipdata; + + psys_adev = ipu7_bus_initialize_device(pdev, parent, pdata, ctrl, + IPU_PSYS_NAME); + if (IS_ERR(psys_adev)) { + dev_err_probe(&pdev->dev, PTR_ERR(psys_adev), + "ipu7_bus_initialize_device psys failed\n"); + kfree(pdata); + return ERR_CAST(psys_adev); + } + + psys_adev->mmu = ipu7_mmu_init(&pdev->dev, base, PSYS_MMID, + &ipdata->hw_variant); + if (IS_ERR(psys_adev->mmu)) { + dev_err_probe(&pdev->dev, PTR_ERR(psys_adev->mmu), + "ipu7_mmu_init(psys_adev->mmu) failed\n"); + put_device(&psys_adev->auxdev.dev); + kfree(pdata); + return ERR_CAST(psys_adev->mmu); + } + + psys_adev->mmu->dev = &psys_adev->auxdev.dev; + psys_adev->subsys = IPU_PS; + + ret = ipu7_bus_add_device(psys_adev); + if (ret) { + kfree(pdata); + return ERR_PTR(ret); + } + + return psys_adev; +} + +static struct ia_gofo_msg_log_info_ts fw_error_log[IPU_SUBSYS_NUM]; +void ipu7_dump_fw_error_log(const struct ipu7_bus_device *adev) +{ + void __iomem *reg = adev->isp->base + ((adev->subsys == IPU_IS) ? + BUTTRESS_REG_FW_GP24 : + BUTTRESS_REG_FW_GP8); + + memcpy_fromio(&fw_error_log[adev->subsys], reg, + sizeof(fw_error_log[adev->subsys])); +} +EXPORT_SYMBOL_NS_GPL(ipu7_dump_fw_error_log, "INTEL_IPU7"); + +static int ipu7_pci_config_setup(struct pci_dev *dev) +{ + u16 pci_command; + int ret; + + pci_read_config_word(dev, PCI_COMMAND, &pci_command); + pci_command |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + pci_write_config_word(dev, PCI_COMMAND, pci_command); + + ret = pci_enable_msi(dev); + if (ret) + dev_err(&dev->dev, "Failed to enable msi (%d)\n", ret); + + return ret; +} + +static int ipu7_map_fw_code_region(struct ipu7_bus_device *sys, + void *data, size_t size) +{ + struct device *dev = &sys->auxdev.dev; + struct ipu7_bus_device *adev = to_ipu7_bus_device(dev); + struct sg_table *sgt = &sys->fw_sgt; + struct ipu7_device *isp = adev->isp; + struct pci_dev *pdev = isp->pdev; + unsigned long n_pages, i; + unsigned long attr = 0; + struct page **pages; + int ret; + + n_pages = PFN_UP(size); + + pages = kmalloc_array(n_pages, sizeof(*pages), GFP_KERNEL); + if (!pages) + return -ENOMEM; + + for (i = 0; i < n_pages; i++) { + struct page *p = vmalloc_to_page(data); + + if (!p) { + ret = -ENODEV; + goto out; + } + + pages[i] = p; + data += PAGE_SIZE; + } + + ret = sg_alloc_table_from_pages(sgt, pages, n_pages, 0, size, + GFP_KERNEL); + if (ret) { + ret = -ENOMEM; + goto out; + } + + if (!isp->secure_mode) + attr |= DMA_ATTR_RESERVE_REGION; + + ret = dma_map_sgtable(&pdev->dev, sgt, DMA_BIDIRECTIONAL, 0); + if (ret < 0) { + dev_err(dev, "map fw code[%lu pages %u nents] failed\n", + n_pages, sgt->nents); + ret = -ENOMEM; + sg_free_table(sgt); + goto out; + } + + ret = ipu7_dma_map_sgtable(sys, sgt, DMA_BIDIRECTIONAL, attr); + if (ret) { + dma_unmap_sgtable(&pdev->dev, sgt, DMA_BIDIRECTIONAL, 0); + sg_free_table(sgt); + goto out; + } + + ipu7_dma_sync_sgtable(sys, sgt); + + dev_dbg(dev, "fw code region mapped at 0x%pad entries %d\n", + &sgt->sgl->dma_address, sgt->nents); + +out: + kfree(pages); + + return ret; +} + +static void ipu7_unmap_fw_code_region(struct ipu7_bus_device *sys) +{ + struct pci_dev *pdev = sys->isp->pdev; + struct sg_table *sgt = &sys->fw_sgt; + + ipu7_dma_unmap_sgtable(sys, sgt, DMA_BIDIRECTIONAL, 0); + dma_unmap_sgtable(&pdev->dev, sgt, DMA_BIDIRECTIONAL, 0); + sg_free_table(sgt); +} + +static int ipu7_init_fw_code_region_by_sys(struct ipu7_bus_device *sys, + const char *sys_name) +{ + struct device *dev = &sys->auxdev.dev; + struct ipu7_device *isp = sys->isp; + int ret; + + /* Copy FW binaries to specific location. */ + ret = ipu7_cpd_copy_binary(isp->cpd_fw->data, sys_name, + isp->fw_code_region, &sys->fw_entry); + if (ret) { + dev_err(dev, "%s binary not found.\n", sys_name); + return ret; + } + + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "Failed to get runtime PM\n"); + return ret; + } + + ret = ipu7_mmu_hw_init(sys->mmu); + if (ret) { + dev_err(dev, "Failed to set mmu hw\n"); + pm_runtime_put(dev); + return ret; + } + + /* Map code region. */ + ret = ipu7_map_fw_code_region(sys, isp->fw_code_region, + IPU_FW_CODE_REGION_SIZE); + if (ret) + dev_err(dev, "Failed to map fw code region for %s.\n", + sys_name); + + ipu7_mmu_hw_cleanup(sys->mmu); + pm_runtime_put(dev); + + return ret; +} + +static int ipu7_init_fw_code_region(struct ipu7_device *isp) +{ + int ret; + + /* + * Allocate and map memory for FW execution. + * Not required in secure mode, in which FW runs in IMR. + */ + isp->fw_code_region = vmalloc(IPU_FW_CODE_REGION_SIZE); + if (!isp->fw_code_region) + return -ENOMEM; + + ret = ipu7_init_fw_code_region_by_sys(isp->isys, "isys"); + if (ret) + goto fail_init; + + ret = ipu7_init_fw_code_region_by_sys(isp->psys, "psys"); + if (ret) + goto fail_init; + + return 0; + +fail_init: + vfree(isp->fw_code_region); + + return ret; +} + +static int ipu7_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct ipu_buttress_ctrl *isys_ctrl = NULL, *psys_ctrl = NULL; + struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev); + const struct ipu_buttress_ctrl *isys_buttress_ctrl; + const struct ipu_buttress_ctrl *psys_buttress_ctrl; + struct ipu_isys_internal_pdata *isys_ipdata; + struct ipu_psys_internal_pdata *psys_ipdata; + unsigned int dma_mask = IPU_DMA_MASK; + struct device *dev = &pdev->dev; + void __iomem *isys_base = NULL; + void __iomem *psys_base = NULL; + phys_addr_t phys, pb_phys; + struct ipu7_device *isp; + u32 is_es; + int ret; + + if (!fwnode || fwnode_property_read_u32(fwnode, "is_es", &is_es)) + is_es = 0; + + isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL); + if (!isp) + return -ENOMEM; + + dev_set_name(dev, "intel-ipu7"); + isp->pdev = pdev; + INIT_LIST_HEAD(&isp->devices); + + ret = pcim_enable_device(pdev); + if (ret) + return dev_err_probe(dev, ret, "Enable PCI device failed\n"); + + dev_info(dev, "Device 0x%x (rev: 0x%x)\n", + pdev->device, pdev->revision); + + phys = pci_resource_start(pdev, IPU_PCI_BAR); + pb_phys = pci_resource_start(pdev, IPU_PCI_PBBAR); + dev_info(dev, "IPU7 PCI BAR0 base %pap BAR2 base %pap\n", + &phys, &pb_phys); + + isp->base = pcim_iomap_region(pdev, IPU_PCI_BAR, IPU_NAME); + if (IS_ERR(isp->base)) + return dev_err_probe(dev, PTR_ERR(isp->base), + "Failed to I/O memory remapping bar %u\n", + IPU_PCI_BAR); + + isp->pb_base = pcim_iomap_region(pdev, IPU_PCI_PBBAR, IPU_NAME); + if (IS_ERR(isp->pb_base)) + return dev_err_probe(dev, PTR_ERR(isp->pb_base), + "Failed to I/O memory remapping bar %u\n", + IPU_PCI_PBBAR); + + dev_info(dev, "IPU7 PCI BAR0 mapped at %p\n BAR2 mapped at %p\n", + isp->base, isp->pb_base); + + pci_set_drvdata(pdev, isp); + pci_set_master(pdev); + + switch (id->device) { + case IPU7_PCI_ID: + isp->hw_ver = IPU_VER_7; + isp->cpd_fw_name = IPU7_FIRMWARE_NAME; + isys_ipdata = &ipu7_isys_ipdata; + psys_ipdata = &ipu7_psys_ipdata; + isys_buttress_ctrl = &ipu7_isys_buttress_ctrl; + psys_buttress_ctrl = &ipu7_psys_buttress_ctrl; + break; + case IPU7P5_PCI_ID: + isp->hw_ver = IPU_VER_7P5; + isp->cpd_fw_name = IPU7P5_FIRMWARE_NAME; + isys_ipdata = &ipu7p5_isys_ipdata; + psys_ipdata = &ipu7p5_psys_ipdata; + isys_buttress_ctrl = &ipu7_isys_buttress_ctrl; + psys_buttress_ctrl = &ipu7_psys_buttress_ctrl; + break; + case IPU8_PCI_ID: + isp->hw_ver = IPU_VER_8; + isp->cpd_fw_name = IPU8_FIRMWARE_NAME; + isys_ipdata = &ipu8_isys_ipdata; + psys_ipdata = &ipu8_psys_ipdata; + isys_buttress_ctrl = &ipu8_isys_buttress_ctrl; + psys_buttress_ctrl = &ipu8_psys_buttress_ctrl; + break; + default: + WARN(1, "Unsupported IPU device"); + return -ENODEV; + } + + ipu_internal_pdata_init(isys_ipdata, psys_ipdata); + + isys_base = isp->base + isys_ipdata->hw_variant.offset; + psys_base = isp->base + psys_ipdata->hw_variant.offset; + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_mask)); + if (ret) + return dev_err_probe(dev, ret, "Failed to set DMA mask\n"); + + dma_set_max_seg_size(dev, UINT_MAX); + + ret = ipu7_pci_config_setup(pdev); + if (ret) + return ret; + + ret = ipu_buttress_init(isp); + if (ret) + return ret; + + dev_info(dev, "firmware cpd file: %s\n", isp->cpd_fw_name); + + ret = request_firmware(&isp->cpd_fw, isp->cpd_fw_name, dev); + if (ret) { + dev_err_probe(dev, ret, + "Requesting signed firmware %s failed\n", + isp->cpd_fw_name); + goto buttress_exit; + } + + ret = ipu7_cpd_validate_cpd_file(isp, isp->cpd_fw->data, + isp->cpd_fw->size); + if (ret) { + dev_err_probe(dev, ret, "Failed to validate cpd\n"); + goto out_ipu_bus_del_devices; + } + + isys_ctrl = devm_kmemdup(dev, isys_buttress_ctrl, + sizeof(*isys_buttress_ctrl), GFP_KERNEL); + if (!isys_ctrl) { + ret = -ENOMEM; + goto out_ipu_bus_del_devices; + } + + isp->isys = ipu7_isys_init(pdev, dev, isys_ctrl, isys_base, + isys_ipdata, 0); + if (IS_ERR(isp->isys)) { + ret = PTR_ERR(isp->isys); + goto out_ipu_bus_del_devices; + } + + psys_ctrl = devm_kmemdup(dev, psys_buttress_ctrl, + sizeof(*psys_buttress_ctrl), GFP_KERNEL); + if (!psys_ctrl) { + ret = -ENOMEM; + goto out_ipu_bus_del_devices; + } + + isp->psys = ipu7_psys_init(pdev, &isp->isys->auxdev.dev, + psys_ctrl, psys_base, + psys_ipdata, 0); + if (IS_ERR(isp->psys)) { + ret = PTR_ERR(isp->psys); + goto out_ipu_bus_del_devices; + } + + ret = devm_request_threaded_irq(dev, pdev->irq, + ipu_buttress_isr, + ipu_buttress_isr_threaded, + IRQF_SHARED, IPU_NAME, isp); + if (ret) + goto out_ipu_bus_del_devices; + + if (!isp->secure_mode) { + ret = ipu7_init_fw_code_region(isp); + if (ret) + goto out_ipu_bus_del_devices; + } else { + ret = pm_runtime_get_sync(&isp->psys->auxdev.dev); + if (ret < 0) { + dev_err(&isp->psys->auxdev.dev, + "Failed to get runtime PM\n"); + goto out_ipu_bus_del_devices; + } + + ret = ipu7_mmu_hw_init(isp->psys->mmu); + if (ret) { + dev_err_probe(&isp->pdev->dev, ret, + "Failed to init MMU hardware\n"); + goto out_ipu_bus_del_devices; + } + + ret = ipu7_map_fw_code_region(isp->psys, + (void *)isp->cpd_fw->data, + isp->cpd_fw->size); + if (ret) { + dev_err_probe(&isp->pdev->dev, ret, + "failed to map fw image\n"); + goto out_ipu_bus_del_devices; + } + + ret = ipu_buttress_authenticate(isp); + if (ret) { + dev_err_probe(&isp->pdev->dev, ret, + "FW authentication failed\n"); + goto out_ipu_bus_del_devices; + } + + ipu7_mmu_hw_cleanup(isp->psys->mmu); + pm_runtime_put(&isp->psys->auxdev.dev); + } + + pm_runtime_put_noidle(dev); + pm_runtime_allow(dev); + + isp->ipu7_bus_ready_to_probe = true; + + return 0; + +out_ipu_bus_del_devices: + if (!IS_ERR_OR_NULL(isp->isys) && isp->isys->fw_sgt.nents) + ipu7_unmap_fw_code_region(isp->isys); + if (!IS_ERR_OR_NULL(isp->psys) && isp->psys->fw_sgt.nents) + ipu7_unmap_fw_code_region(isp->psys); + if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu)) + ipu7_mmu_cleanup(isp->psys->mmu); + if (!IS_ERR_OR_NULL(isp->isys) && !IS_ERR_OR_NULL(isp->isys->mmu)) + ipu7_mmu_cleanup(isp->isys->mmu); + if (!IS_ERR_OR_NULL(isp->psys)) + pm_runtime_put(&isp->psys->auxdev.dev); + ipu7_bus_del_devices(pdev); + release_firmware(isp->cpd_fw); +buttress_exit: + ipu_buttress_exit(isp); + + return ret; +} + +static void ipu7_pci_remove(struct pci_dev *pdev) +{ + struct ipu7_device *isp = pci_get_drvdata(pdev); + + if (!IS_ERR_OR_NULL(isp->isys) && isp->isys->fw_sgt.nents) + ipu7_unmap_fw_code_region(isp->isys); + if (!IS_ERR_OR_NULL(isp->psys) && isp->psys->fw_sgt.nents) + ipu7_unmap_fw_code_region(isp->psys); + + if (!IS_ERR_OR_NULL(isp->fw_code_region)) + vfree(isp->fw_code_region); + + ipu7_bus_del_devices(pdev); + + pm_runtime_forbid(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + + ipu_buttress_exit(isp); + + release_firmware(isp->cpd_fw); + + ipu7_mmu_cleanup(isp->psys->mmu); + ipu7_mmu_cleanup(isp->isys->mmu); +} + +static void ipu7_pci_reset_prepare(struct pci_dev *pdev) +{ + struct ipu7_device *isp = pci_get_drvdata(pdev); + + dev_warn(&pdev->dev, "FLR prepare\n"); + pm_runtime_forbid(&isp->pdev->dev); +} + +static void ipu7_pci_reset_done(struct pci_dev *pdev) +{ + struct ipu7_device *isp = pci_get_drvdata(pdev); + + ipu_buttress_restore(isp); + if (isp->secure_mode) + ipu_buttress_reset_authentication(isp); + + isp->ipc_reinit = true; + pm_runtime_allow(&isp->pdev->dev); + + dev_warn(&pdev->dev, "FLR completed\n"); +} + +/* + * PCI base driver code requires driver to provide these to enable + * PCI device level PM state transitions (D0<->D3) + */ +static int ipu7_suspend(struct device *dev) +{ + return 0; +} + +static int ipu7_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct ipu7_device *isp = pci_get_drvdata(pdev); + struct ipu_buttress *b = &isp->buttress; + int ret; + + isp->secure_mode = ipu_buttress_get_secure_mode(isp); + dev_info(dev, "IPU7 in %s mode\n", + isp->secure_mode ? "secure" : "non-secure"); + + ipu_buttress_restore(isp); + + ret = ipu_buttress_ipc_reset(isp, &b->cse); + if (ret) + dev_err(dev, "IPC reset protocol failed!\n"); + + ret = pm_runtime_get_sync(&isp->psys->auxdev.dev); + if (ret < 0) { + dev_err(dev, "Failed to get runtime PM\n"); + return 0; + } + + ret = ipu_buttress_authenticate(isp); + if (ret) + dev_err(dev, "FW authentication failed(%d)\n", ret); + + pm_runtime_put(&isp->psys->auxdev.dev); + + return 0; +} + +static int ipu7_runtime_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct ipu7_device *isp = pci_get_drvdata(pdev); + int ret; + + ipu_buttress_restore(isp); + + if (isp->ipc_reinit) { + struct ipu_buttress *b = &isp->buttress; + + isp->ipc_reinit = false; + ret = ipu_buttress_ipc_reset(isp, &b->cse); + if (ret) + dev_err(dev, "IPC reset protocol failed!\n"); + } + + return 0; +} + +static const struct dev_pm_ops ipu7_pm_ops = { + SYSTEM_SLEEP_PM_OPS(&ipu7_suspend, &ipu7_resume) + RUNTIME_PM_OPS(&ipu7_suspend, &ipu7_runtime_resume, NULL) +}; + +static const struct pci_device_id ipu7_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU7_PCI_ID)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU7P5_PCI_ID)}, + {0,} +}; +MODULE_DEVICE_TABLE(pci, ipu7_pci_tbl); + +static const struct pci_error_handlers pci_err_handlers = { + .reset_prepare = ipu7_pci_reset_prepare, + .reset_done = ipu7_pci_reset_done, +}; + +static struct pci_driver ipu7_pci_driver = { + .name = IPU_NAME, + .id_table = ipu7_pci_tbl, + .probe = ipu7_pci_probe, + .remove = ipu7_pci_remove, + .driver = { + .pm = &ipu7_pm_ops, + }, + .err_handler = &pci_err_handlers, +}; + +module_pci_driver(ipu7_pci_driver); + +MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); +MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>"); +MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>"); +MODULE_AUTHOR("Qingwu Zhang <qingwu.zhang@intel.com>"); +MODULE_AUTHOR("Intel"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Intel ipu7 pci driver"); diff --git a/drivers/staging/media/ipu7/ipu7.h b/drivers/staging/media/ipu7/ipu7.h new file mode 100644 index 0000000000000..ac8ac0689468e --- /dev/null +++ b/drivers/staging/media/ipu7/ipu7.h @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - 2025 Intel Corporation + */ + +#ifndef IPU7_H +#define IPU7_H + +#include <linux/list.h> +#include <linux/pci.h> +#include <linux/types.h> + +#include "ipu7-buttress.h" + +struct ipu7_bus_device; +struct pci_dev; +struct firmware; + +#define IPU_NAME "intel-ipu7" +#define IPU_MEDIA_DEV_MODEL_NAME "ipu7" + +#define IPU7_FIRMWARE_NAME "intel/ipu/ipu7_fw.bin" +#define IPU7P5_FIRMWARE_NAME "intel/ipu/ipu7ptl_fw.bin" +#define IPU8_FIRMWARE_NAME "intel/ipu/ipu8_fw.bin" + +#define IPU7_ISYS_NUM_STREAMS 12 + +#define IPU7_PCI_ID 0x645d +#define IPU7P5_PCI_ID 0xb05d +#define IPU8_PCI_ID 0xd719 + +#define FW_LOG_BUF_SIZE (2 * 1024 * 1024) + +enum ipu_version { + IPU_VER_INVALID = 0, + IPU_VER_7 = 1, + IPU_VER_7P5 = 2, + IPU_VER_8 = 3, +}; + +static inline bool is_ipu7p5(u8 hw_ver) +{ + return hw_ver == IPU_VER_7P5; +} + +static inline bool is_ipu7(u8 hw_ver) +{ + return hw_ver == IPU_VER_7; +} + +static inline bool is_ipu8(u8 hw_ver) +{ + return hw_ver == IPU_VER_8; +} + +#define IPU_UNIFIED_OFFSET 0 + +/* + * 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 + +#define IPU_FW_CODE_REGION_SIZE 0x1000000 /* 16MB */ +#define IPU_FW_CODE_REGION_START 0x4000000 /* 64MB */ +#define IPU_FW_CODE_REGION_END (IPU_FW_CODE_REGION_START + \ + IPU_FW_CODE_REGION_SIZE) /* 80MB */ + +struct ipu7_device { + struct pci_dev *pdev; + struct list_head devices; + struct ipu7_bus_device *isys; + struct ipu7_bus_device *psys; + struct ipu_buttress buttress; + + const struct firmware *cpd_fw; + const char *cpd_fw_name; + /* Only for non-secure mode. */ + void *fw_code_region; + + void __iomem *base; + void __iomem *pb_base; + u8 hw_ver; + bool ipc_reinit; + bool secure_mode; + bool ipu7_bus_ready_to_probe; +}; + +#define IPU_DMA_MASK 39 +#define IPU_LIB_CALL_TIMEOUT_MS 2000 +#define IPU_PSYS_CMD_TIMEOUT_MS 2000 +#define IPU_PSYS_OPEN_CLOSE_TIMEOUT_US 50 +#define IPU_PSYS_OPEN_CLOSE_RETRY (10000 / IPU_PSYS_OPEN_CLOSE_TIMEOUT_US) + +#define IPU_ISYS_NAME "isys" +#define IPU_PSYS_NAME "psys" + +#define IPU_MMU_ADDR_BITS 32 +/* FW is accessible within the first 2 GiB only in non-secure mode. */ +#define IPU_MMU_ADDR_BITS_NON_SECURE 31 + +#define IPU7_IS_MMU_NUM 4U +#define IPU7_PS_MMU_NUM 4U +#define IPU7P5_IS_MMU_NUM 4U +#define IPU7P5_PS_MMU_NUM 4U +#define IPU8_IS_MMU_NUM 5U +#define IPU8_PS_MMU_NUM 4U +#define IPU_MMU_MAX_NUM 5U /* max(IS, PS) */ +#define IPU_MMU_MAX_TLB_L1_STREAMS 40U +#define IPU_MMU_MAX_TLB_L2_STREAMS 40U +#define IPU_ZLX_MAX_NUM 32U +#define IPU_ZLX_POOL_NUM 8U +#define IPU_UAO_PLANE_MAX_NUM 64U + +/* + * 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 IPU + */ +#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 + +/* 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 + +struct ipu7_mmu_hw { + char name[32]; + + void __iomem *base; + void __iomem *zlx_base; + void __iomem *uao_base; + + u32 offset; + u32 zlx_offset; + u32 uao_offset; + + u32 info_bits; + u32 refill; + u32 collapse_en_bitmap; + u32 at_sp_arb_cfg; + + u32 l1_block; + u32 l2_block; + + u8 nr_l1streams; + u8 nr_l2streams; + u32 l1_block_sz[IPU_MMU_MAX_TLB_L1_STREAMS]; + u32 l2_block_sz[IPU_MMU_MAX_TLB_L2_STREAMS]; + + u8 zlx_nr; + u32 zlx_axi_pool[IPU_ZLX_POOL_NUM]; + u32 zlx_en[IPU_ZLX_MAX_NUM]; + u32 zlx_conf[IPU_ZLX_MAX_NUM]; + + u32 uao_p_num; + u32 uao_p2tlb[IPU_UAO_PLANE_MAX_NUM]; +}; + +struct ipu7_mmu_pdata { + u32 nr_mmus; + struct ipu7_mmu_hw mmu_hw[IPU_MMU_MAX_NUM]; + int mmid; +}; + +struct ipu7_isys_csi2_pdata { + void __iomem *base; +}; + +struct ipu7_isys_internal_csi2_pdata { + u32 nports; + u32 const *offsets; + u32 gpreg; +}; + +struct ipu7_hw_variants { + unsigned long offset; + u32 nr_mmus; + struct ipu7_mmu_hw mmu_hw[IPU_MMU_MAX_NUM]; + 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 ipu7_isys_internal_csi2_pdata csi2; + struct ipu7_hw_variants hw_variant; + u32 num_parallel_streams; + u32 isys_dma_overshoot; +}; + +struct ipu7_isys_pdata { + void __iomem *base; + const struct ipu_isys_internal_pdata *ipdata; +}; + +struct ipu_psys_internal_pdata { + struct ipu7_hw_variants hw_variant; +}; + +struct ipu7_psys_pdata { + void __iomem *base; + const struct ipu_psys_internal_pdata *ipdata; +}; + +int request_cpd_fw(const struct firmware **firmware_p, const char *name, + struct device *device); +void ipu_internal_pdata_init(struct ipu_isys_internal_pdata *isys_ipdata, + struct ipu_psys_internal_pdata *psys_ipdata); +void ipu7_dump_fw_error_log(const struct ipu7_bus_device *adev); +#endif /* IPU7_H */ diff --git a/drivers/staging/media/rkvdec/Kconfig b/drivers/staging/media/rkvdec/Kconfig deleted file mode 100644 index 5f3bdd848a2cf..0000000000000 --- a/drivers/staging/media/rkvdec/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config VIDEO_ROCKCHIP_VDEC - tristate "Rockchip Video Decoder driver" - depends on ARCH_ROCKCHIP || COMPILE_TEST - depends on VIDEO_DEV - select MEDIA_CONTROLLER - select VIDEOBUF2_DMA_CONTIG - select VIDEOBUF2_VMALLOC - select V4L2_MEM2MEM_DEV - select V4L2_H264 - select V4L2_VP9 - help - Support for the Rockchip Video Decoder IP present on Rockchip SoCs, - which accelerates video decoding. - To compile this driver as a module, choose M here: the module - will be called rockchip-vdec. diff --git a/drivers/staging/media/rkvdec/Makefile b/drivers/staging/media/rkvdec/Makefile deleted file mode 100644 index cb86b429cfaac..0000000000000 --- a/drivers/staging/media/rkvdec/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rockchip-vdec.o - -rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-vp9.o diff --git a/drivers/staging/media/rkvdec/TODO b/drivers/staging/media/rkvdec/TODO deleted file mode 100644 index 2c0779383276e..0000000000000 --- a/drivers/staging/media/rkvdec/TODO +++ /dev/null @@ -1,11 +0,0 @@ -* Support for HEVC is planned for this driver. - - Given the V4L controls for that CODEC will be part of - the uABI, it will be required to have the driver in staging. - - For this reason, we are keeping this driver in staging for now. - -* Evaluate introducing a helper to consolidate duplicated - code in rkvdec_request_validate and cedrus_request_validate. - The helper needs to the driver private data associated with - the videobuf2 queue, from a media request. diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c deleted file mode 100644 index d14b4d173448d..0000000000000 --- a/drivers/staging/media/rkvdec/rkvdec-h264.c +++ /dev/null @@ -1,1212 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip Video Decoder H264 backend - * - * Copyright (C) 2019 Collabora, Ltd. - * Boris Brezillon <boris.brezillon@collabora.com> - * - * Copyright (C) 2016 Rockchip Electronics Co., Ltd. - * Jeffy Chen <jeffy.chen@rock-chips.com> - */ - -#include <media/v4l2-h264.h> -#include <media/v4l2-mem2mem.h> - -#include "rkvdec.h" -#include "rkvdec-regs.h" - -/* Size with u32 units. */ -#define RKV_CABAC_INIT_BUFFER_SIZE (3680 + 128) -#define RKV_RPS_SIZE ((128 + 128) / 4) -#define RKV_ERROR_INFO_SIZE (256 * 144 * 4) - -#define RKVDEC_NUM_REFLIST 3 - -struct rkvdec_h264_scaling_list { - u8 scaling_list_4x4[6][16]; - u8 scaling_list_8x8[6][64]; - u8 padding[128]; -}; - -struct rkvdec_sps_pps_packet { - u32 info[8]; -}; - -struct rkvdec_ps_field { - u16 offset; - u8 len; -}; - -#define PS_FIELD(_offset, _len) \ - ((struct rkvdec_ps_field){ _offset, _len }) - -#define SEQ_PARAMETER_SET_ID PS_FIELD(0, 4) -#define PROFILE_IDC PS_FIELD(4, 8) -#define CONSTRAINT_SET3_FLAG PS_FIELD(12, 1) -#define CHROMA_FORMAT_IDC PS_FIELD(13, 2) -#define BIT_DEPTH_LUMA PS_FIELD(15, 3) -#define BIT_DEPTH_CHROMA PS_FIELD(18, 3) -#define QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG PS_FIELD(21, 1) -#define LOG2_MAX_FRAME_NUM_MINUS4 PS_FIELD(22, 4) -#define MAX_NUM_REF_FRAMES PS_FIELD(26, 5) -#define PIC_ORDER_CNT_TYPE PS_FIELD(31, 2) -#define LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4 PS_FIELD(33, 4) -#define DELTA_PIC_ORDER_ALWAYS_ZERO_FLAG PS_FIELD(37, 1) -#define PIC_WIDTH_IN_MBS PS_FIELD(38, 9) -#define PIC_HEIGHT_IN_MBS PS_FIELD(47, 9) -#define FRAME_MBS_ONLY_FLAG PS_FIELD(56, 1) -#define MB_ADAPTIVE_FRAME_FIELD_FLAG PS_FIELD(57, 1) -#define DIRECT_8X8_INFERENCE_FLAG PS_FIELD(58, 1) -#define MVC_EXTENSION_ENABLE PS_FIELD(59, 1) -#define NUM_VIEWS PS_FIELD(60, 2) -#define VIEW_ID(i) PS_FIELD(62 + ((i) * 10), 10) -#define NUM_ANCHOR_REFS_L(i) PS_FIELD(82 + ((i) * 11), 1) -#define ANCHOR_REF_L(i) PS_FIELD(83 + ((i) * 11), 10) -#define NUM_NON_ANCHOR_REFS_L(i) PS_FIELD(104 + ((i) * 11), 1) -#define NON_ANCHOR_REFS_L(i) PS_FIELD(105 + ((i) * 11), 10) -#define PIC_PARAMETER_SET_ID PS_FIELD(128, 8) -#define PPS_SEQ_PARAMETER_SET_ID PS_FIELD(136, 5) -#define ENTROPY_CODING_MODE_FLAG PS_FIELD(141, 1) -#define BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT_FLAG PS_FIELD(142, 1) -#define NUM_REF_IDX_L_DEFAULT_ACTIVE_MINUS1(i) PS_FIELD(143 + ((i) * 5), 5) -#define WEIGHTED_PRED_FLAG PS_FIELD(153, 1) -#define WEIGHTED_BIPRED_IDC PS_FIELD(154, 2) -#define PIC_INIT_QP_MINUS26 PS_FIELD(156, 7) -#define PIC_INIT_QS_MINUS26 PS_FIELD(163, 6) -#define CHROMA_QP_INDEX_OFFSET PS_FIELD(169, 5) -#define DEBLOCKING_FILTER_CONTROL_PRESENT_FLAG PS_FIELD(174, 1) -#define CONSTRAINED_INTRA_PRED_FLAG PS_FIELD(175, 1) -#define REDUNDANT_PIC_CNT_PRESENT PS_FIELD(176, 1) -#define TRANSFORM_8X8_MODE_FLAG PS_FIELD(177, 1) -#define SECOND_CHROMA_QP_INDEX_OFFSET PS_FIELD(178, 5) -#define SCALING_LIST_ENABLE_FLAG PS_FIELD(183, 1) -#define SCALING_LIST_ADDRESS PS_FIELD(184, 32) -#define IS_LONG_TERM(i) PS_FIELD(216 + (i), 1) - -#define DPB_OFFS(i, j) (288 + ((j) * 32 * 7) + ((i) * 7)) -#define DPB_INFO(i, j) PS_FIELD(DPB_OFFS(i, j), 5) -#define BOTTOM_FLAG(i, j) PS_FIELD(DPB_OFFS(i, j) + 5, 1) -#define VIEW_INDEX_OFF(i, j) PS_FIELD(DPB_OFFS(i, j) + 6, 1) - -/* Data structure describing auxiliary buffer format. */ -struct rkvdec_h264_priv_tbl { - s8 cabac_table[4][464][2]; - struct rkvdec_h264_scaling_list scaling_list; - u32 rps[RKV_RPS_SIZE]; - struct rkvdec_sps_pps_packet param_set[256]; - u8 err_info[RKV_ERROR_INFO_SIZE]; -}; - -struct rkvdec_h264_reflists { - struct v4l2_h264_reference p[V4L2_H264_REF_LIST_LEN]; - struct v4l2_h264_reference b0[V4L2_H264_REF_LIST_LEN]; - struct v4l2_h264_reference b1[V4L2_H264_REF_LIST_LEN]; -}; - -struct rkvdec_h264_run { - struct rkvdec_run base; - const struct v4l2_ctrl_h264_decode_params *decode_params; - const struct v4l2_ctrl_h264_sps *sps; - const struct v4l2_ctrl_h264_pps *pps; - const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; - struct vb2_buffer *ref_buf[V4L2_H264_NUM_DPB_ENTRIES]; -}; - -struct rkvdec_h264_ctx { - struct rkvdec_aux_buf priv_tbl; - struct rkvdec_h264_reflists reflists; -}; - -#define CABAC_ENTRY(ctxidx, idc0_m, idc0_n, idc1_m, idc1_n, \ - idc2_m, idc2_n, intra_m, intra_n) \ - [0][(ctxidx)] = {idc0_m, idc0_n}, \ - [1][(ctxidx)] = {idc1_m, idc1_n}, \ - [2][(ctxidx)] = {idc2_m, idc2_n}, \ - [3][(ctxidx)] = {intra_m, intra_n} - -/* - * Constant CABAC table. - * Built from the tables described in section '9.3.1.1 Initialisation process - * for context variables' of the H264 spec. - */ -static const s8 rkvdec_h264_cabac_table[4][464][2] = { - /* Table 9-12 – Values of variables m and n for ctxIdx from 0 to 10 */ - CABAC_ENTRY(0, 20, -15, 20, -15, 20, -15, 20, -15), - CABAC_ENTRY(1, 2, 54, 2, 54, 2, 54, 2, 54), - CABAC_ENTRY(2, 3, 74, 3, 74, 3, 74, 3, 74), - CABAC_ENTRY(3, 20, -15, 20, -15, 20, -15, 20, -15), - CABAC_ENTRY(4, 2, 54, 2, 54, 2, 54, 2, 54), - CABAC_ENTRY(5, 3, 74, 3, 74, 3, 74, 3, 74), - CABAC_ENTRY(6, -28, 127, -28, 127, -28, 127, -28, 127), - CABAC_ENTRY(7, -23, 104, -23, 104, -23, 104, -23, 104), - CABAC_ENTRY(8, -6, 53, -6, 53, -6, 53, -6, 53), - CABAC_ENTRY(9, -1, 54, -1, 54, -1, 54, -1, 54), - CABAC_ENTRY(10, 7, 51, 7, 51, 7, 51, 7, 51), - - /* Table 9-13 – Values of variables m and n for ctxIdx from 11 to 23 */ - CABAC_ENTRY(11, 23, 33, 22, 25, 29, 16, 0, 0), - CABAC_ENTRY(12, 23, 2, 34, 0, 25, 0, 0, 0), - CABAC_ENTRY(13, 21, 0, 16, 0, 14, 0, 0, 0), - CABAC_ENTRY(14, 1, 9, -2, 9, -10, 51, 0, 0), - CABAC_ENTRY(15, 0, 49, 4, 41, -3, 62, 0, 0), - CABAC_ENTRY(16, -37, 118, -29, 118, -27, 99, 0, 0), - CABAC_ENTRY(17, 5, 57, 2, 65, 26, 16, 0, 0), - CABAC_ENTRY(18, -13, 78, -6, 71, -4, 85, 0, 0), - CABAC_ENTRY(19, -11, 65, -13, 79, -24, 102, 0, 0), - CABAC_ENTRY(20, 1, 62, 5, 52, 5, 57, 0, 0), - CABAC_ENTRY(21, 12, 49, 9, 50, 6, 57, 0, 0), - CABAC_ENTRY(22, -4, 73, -3, 70, -17, 73, 0, 0), - CABAC_ENTRY(23, 17, 50, 10, 54, 14, 57, 0, 0), - - /* Table 9-14 – Values of variables m and n for ctxIdx from 24 to 39 */ - CABAC_ENTRY(24, 18, 64, 26, 34, 20, 40, 0, 0), - CABAC_ENTRY(25, 9, 43, 19, 22, 20, 10, 0, 0), - CABAC_ENTRY(26, 29, 0, 40, 0, 29, 0, 0, 0), - CABAC_ENTRY(27, 26, 67, 57, 2, 54, 0, 0, 0), - CABAC_ENTRY(28, 16, 90, 41, 36, 37, 42, 0, 0), - CABAC_ENTRY(29, 9, 104, 26, 69, 12, 97, 0, 0), - CABAC_ENTRY(30, -46, 127, -45, 127, -32, 127, 0, 0), - CABAC_ENTRY(31, -20, 104, -15, 101, -22, 117, 0, 0), - CABAC_ENTRY(32, 1, 67, -4, 76, -2, 74, 0, 0), - CABAC_ENTRY(33, -13, 78, -6, 71, -4, 85, 0, 0), - CABAC_ENTRY(34, -11, 65, -13, 79, -24, 102, 0, 0), - CABAC_ENTRY(35, 1, 62, 5, 52, 5, 57, 0, 0), - CABAC_ENTRY(36, -6, 86, 6, 69, -6, 93, 0, 0), - CABAC_ENTRY(37, -17, 95, -13, 90, -14, 88, 0, 0), - CABAC_ENTRY(38, -6, 61, 0, 52, -6, 44, 0, 0), - CABAC_ENTRY(39, 9, 45, 8, 43, 4, 55, 0, 0), - - /* Table 9-15 – Values of variables m and n for ctxIdx from 40 to 53 */ - CABAC_ENTRY(40, -3, 69, -2, 69, -11, 89, 0, 0), - CABAC_ENTRY(41, -6, 81, -5, 82, -15, 103, 0, 0), - CABAC_ENTRY(42, -11, 96, -10, 96, -21, 116, 0, 0), - CABAC_ENTRY(43, 6, 55, 2, 59, 19, 57, 0, 0), - CABAC_ENTRY(44, 7, 67, 2, 75, 20, 58, 0, 0), - CABAC_ENTRY(45, -5, 86, -3, 87, 4, 84, 0, 0), - CABAC_ENTRY(46, 2, 88, -3, 100, 6, 96, 0, 0), - CABAC_ENTRY(47, 0, 58, 1, 56, 1, 63, 0, 0), - CABAC_ENTRY(48, -3, 76, -3, 74, -5, 85, 0, 0), - CABAC_ENTRY(49, -10, 94, -6, 85, -13, 106, 0, 0), - CABAC_ENTRY(50, 5, 54, 0, 59, 5, 63, 0, 0), - CABAC_ENTRY(51, 4, 69, -3, 81, 6, 75, 0, 0), - CABAC_ENTRY(52, -3, 81, -7, 86, -3, 90, 0, 0), - CABAC_ENTRY(53, 0, 88, -5, 95, -1, 101, 0, 0), - - /* Table 9-16 – Values of variables m and n for ctxIdx from 54 to 59 */ - CABAC_ENTRY(54, -7, 67, -1, 66, 3, 55, 0, 0), - CABAC_ENTRY(55, -5, 74, -1, 77, -4, 79, 0, 0), - CABAC_ENTRY(56, -4, 74, 1, 70, -2, 75, 0, 0), - CABAC_ENTRY(57, -5, 80, -2, 86, -12, 97, 0, 0), - CABAC_ENTRY(58, -7, 72, -5, 72, -7, 50, 0, 0), - CABAC_ENTRY(59, 1, 58, 0, 61, 1, 60, 0, 0), - - /* Table 9-17 – Values of variables m and n for ctxIdx from 60 to 69 */ - CABAC_ENTRY(60, 0, 41, 0, 41, 0, 41, 0, 41), - CABAC_ENTRY(61, 0, 63, 0, 63, 0, 63, 0, 63), - CABAC_ENTRY(62, 0, 63, 0, 63, 0, 63, 0, 63), - CABAC_ENTRY(63, 0, 63, 0, 63, 0, 63, 0, 63), - CABAC_ENTRY(64, -9, 83, -9, 83, -9, 83, -9, 83), - CABAC_ENTRY(65, 4, 86, 4, 86, 4, 86, 4, 86), - CABAC_ENTRY(66, 0, 97, 0, 97, 0, 97, 0, 97), - CABAC_ENTRY(67, -7, 72, -7, 72, -7, 72, -7, 72), - CABAC_ENTRY(68, 13, 41, 13, 41, 13, 41, 13, 41), - CABAC_ENTRY(69, 3, 62, 3, 62, 3, 62, 3, 62), - - /* Table 9-18 – Values of variables m and n for ctxIdx from 70 to 104 */ - CABAC_ENTRY(70, 0, 45, 13, 15, 7, 34, 0, 11), - CABAC_ENTRY(71, -4, 78, 7, 51, -9, 88, 1, 55), - CABAC_ENTRY(72, -3, 96, 2, 80, -20, 127, 0, 69), - CABAC_ENTRY(73, -27, 126, -39, 127, -36, 127, -17, 127), - CABAC_ENTRY(74, -28, 98, -18, 91, -17, 91, -13, 102), - CABAC_ENTRY(75, -25, 101, -17, 96, -14, 95, 0, 82), - CABAC_ENTRY(76, -23, 67, -26, 81, -25, 84, -7, 74), - CABAC_ENTRY(77, -28, 82, -35, 98, -25, 86, -21, 107), - CABAC_ENTRY(78, -20, 94, -24, 102, -12, 89, -27, 127), - CABAC_ENTRY(79, -16, 83, -23, 97, -17, 91, -31, 127), - CABAC_ENTRY(80, -22, 110, -27, 119, -31, 127, -24, 127), - CABAC_ENTRY(81, -21, 91, -24, 99, -14, 76, -18, 95), - CABAC_ENTRY(82, -18, 102, -21, 110, -18, 103, -27, 127), - CABAC_ENTRY(83, -13, 93, -18, 102, -13, 90, -21, 114), - CABAC_ENTRY(84, -29, 127, -36, 127, -37, 127, -30, 127), - CABAC_ENTRY(85, -7, 92, 0, 80, 11, 80, -17, 123), - CABAC_ENTRY(86, -5, 89, -5, 89, 5, 76, -12, 115), - CABAC_ENTRY(87, -7, 96, -7, 94, 2, 84, -16, 122), - CABAC_ENTRY(88, -13, 108, -4, 92, 5, 78, -11, 115), - CABAC_ENTRY(89, -3, 46, 0, 39, -6, 55, -12, 63), - CABAC_ENTRY(90, -1, 65, 0, 65, 4, 61, -2, 68), - CABAC_ENTRY(91, -1, 57, -15, 84, -14, 83, -15, 84), - CABAC_ENTRY(92, -9, 93, -35, 127, -37, 127, -13, 104), - CABAC_ENTRY(93, -3, 74, -2, 73, -5, 79, -3, 70), - CABAC_ENTRY(94, -9, 92, -12, 104, -11, 104, -8, 93), - CABAC_ENTRY(95, -8, 87, -9, 91, -11, 91, -10, 90), - CABAC_ENTRY(96, -23, 126, -31, 127, -30, 127, -30, 127), - CABAC_ENTRY(97, 5, 54, 3, 55, 0, 65, -1, 74), - CABAC_ENTRY(98, 6, 60, 7, 56, -2, 79, -6, 97), - CABAC_ENTRY(99, 6, 59, 7, 55, 0, 72, -7, 91), - CABAC_ENTRY(100, 6, 69, 8, 61, -4, 92, -20, 127), - CABAC_ENTRY(101, -1, 48, -3, 53, -6, 56, -4, 56), - CABAC_ENTRY(102, 0, 68, 0, 68, 3, 68, -5, 82), - CABAC_ENTRY(103, -4, 69, -7, 74, -8, 71, -7, 76), - CABAC_ENTRY(104, -8, 88, -9, 88, -13, 98, -22, 125), - - /* Table 9-19 – Values of variables m and n for ctxIdx from 105 to 165 */ - CABAC_ENTRY(105, -2, 85, -13, 103, -4, 86, -7, 93), - CABAC_ENTRY(106, -6, 78, -13, 91, -12, 88, -11, 87), - CABAC_ENTRY(107, -1, 75, -9, 89, -5, 82, -3, 77), - CABAC_ENTRY(108, -7, 77, -14, 92, -3, 72, -5, 71), - CABAC_ENTRY(109, 2, 54, -8, 76, -4, 67, -4, 63), - CABAC_ENTRY(110, 5, 50, -12, 87, -8, 72, -4, 68), - CABAC_ENTRY(111, -3, 68, -23, 110, -16, 89, -12, 84), - CABAC_ENTRY(112, 1, 50, -24, 105, -9, 69, -7, 62), - CABAC_ENTRY(113, 6, 42, -10, 78, -1, 59, -7, 65), - CABAC_ENTRY(114, -4, 81, -20, 112, 5, 66, 8, 61), - CABAC_ENTRY(115, 1, 63, -17, 99, 4, 57, 5, 56), - CABAC_ENTRY(116, -4, 70, -78, 127, -4, 71, -2, 66), - CABAC_ENTRY(117, 0, 67, -70, 127, -2, 71, 1, 64), - CABAC_ENTRY(118, 2, 57, -50, 127, 2, 58, 0, 61), - CABAC_ENTRY(119, -2, 76, -46, 127, -1, 74, -2, 78), - CABAC_ENTRY(120, 11, 35, -4, 66, -4, 44, 1, 50), - CABAC_ENTRY(121, 4, 64, -5, 78, -1, 69, 7, 52), - CABAC_ENTRY(122, 1, 61, -4, 71, 0, 62, 10, 35), - CABAC_ENTRY(123, 11, 35, -8, 72, -7, 51, 0, 44), - CABAC_ENTRY(124, 18, 25, 2, 59, -4, 47, 11, 38), - CABAC_ENTRY(125, 12, 24, -1, 55, -6, 42, 1, 45), - CABAC_ENTRY(126, 13, 29, -7, 70, -3, 41, 0, 46), - CABAC_ENTRY(127, 13, 36, -6, 75, -6, 53, 5, 44), - CABAC_ENTRY(128, -10, 93, -8, 89, 8, 76, 31, 17), - CABAC_ENTRY(129, -7, 73, -34, 119, -9, 78, 1, 51), - CABAC_ENTRY(130, -2, 73, -3, 75, -11, 83, 7, 50), - CABAC_ENTRY(131, 13, 46, 32, 20, 9, 52, 28, 19), - CABAC_ENTRY(132, 9, 49, 30, 22, 0, 67, 16, 33), - CABAC_ENTRY(133, -7, 100, -44, 127, -5, 90, 14, 62), - CABAC_ENTRY(134, 9, 53, 0, 54, 1, 67, -13, 108), - CABAC_ENTRY(135, 2, 53, -5, 61, -15, 72, -15, 100), - CABAC_ENTRY(136, 5, 53, 0, 58, -5, 75, -13, 101), - CABAC_ENTRY(137, -2, 61, -1, 60, -8, 80, -13, 91), - CABAC_ENTRY(138, 0, 56, -3, 61, -21, 83, -12, 94), - CABAC_ENTRY(139, 0, 56, -8, 67, -21, 64, -10, 88), - CABAC_ENTRY(140, -13, 63, -25, 84, -13, 31, -16, 84), - CABAC_ENTRY(141, -5, 60, -14, 74, -25, 64, -10, 86), - CABAC_ENTRY(142, -1, 62, -5, 65, -29, 94, -7, 83), - CABAC_ENTRY(143, 4, 57, 5, 52, 9, 75, -13, 87), - CABAC_ENTRY(144, -6, 69, 2, 57, 17, 63, -19, 94), - CABAC_ENTRY(145, 4, 57, 0, 61, -8, 74, 1, 70), - CABAC_ENTRY(146, 14, 39, -9, 69, -5, 35, 0, 72), - CABAC_ENTRY(147, 4, 51, -11, 70, -2, 27, -5, 74), - CABAC_ENTRY(148, 13, 68, 18, 55, 13, 91, 18, 59), - CABAC_ENTRY(149, 3, 64, -4, 71, 3, 65, -8, 102), - CABAC_ENTRY(150, 1, 61, 0, 58, -7, 69, -15, 100), - CABAC_ENTRY(151, 9, 63, 7, 61, 8, 77, 0, 95), - CABAC_ENTRY(152, 7, 50, 9, 41, -10, 66, -4, 75), - CABAC_ENTRY(153, 16, 39, 18, 25, 3, 62, 2, 72), - CABAC_ENTRY(154, 5, 44, 9, 32, -3, 68, -11, 75), - CABAC_ENTRY(155, 4, 52, 5, 43, -20, 81, -3, 71), - CABAC_ENTRY(156, 11, 48, 9, 47, 0, 30, 15, 46), - CABAC_ENTRY(157, -5, 60, 0, 44, 1, 7, -13, 69), - CABAC_ENTRY(158, -1, 59, 0, 51, -3, 23, 0, 62), - CABAC_ENTRY(159, 0, 59, 2, 46, -21, 74, 0, 65), - CABAC_ENTRY(160, 22, 33, 19, 38, 16, 66, 21, 37), - CABAC_ENTRY(161, 5, 44, -4, 66, -23, 124, -15, 72), - CABAC_ENTRY(162, 14, 43, 15, 38, 17, 37, 9, 57), - CABAC_ENTRY(163, -1, 78, 12, 42, 44, -18, 16, 54), - CABAC_ENTRY(164, 0, 60, 9, 34, 50, -34, 0, 62), - CABAC_ENTRY(165, 9, 69, 0, 89, -22, 127, 12, 72), - - /* Table 9-20 – Values of variables m and n for ctxIdx from 166 to 226 */ - CABAC_ENTRY(166, 11, 28, 4, 45, 4, 39, 24, 0), - CABAC_ENTRY(167, 2, 40, 10, 28, 0, 42, 15, 9), - CABAC_ENTRY(168, 3, 44, 10, 31, 7, 34, 8, 25), - CABAC_ENTRY(169, 0, 49, 33, -11, 11, 29, 13, 18), - CABAC_ENTRY(170, 0, 46, 52, -43, 8, 31, 15, 9), - CABAC_ENTRY(171, 2, 44, 18, 15, 6, 37, 13, 19), - CABAC_ENTRY(172, 2, 51, 28, 0, 7, 42, 10, 37), - CABAC_ENTRY(173, 0, 47, 35, -22, 3, 40, 12, 18), - CABAC_ENTRY(174, 4, 39, 38, -25, 8, 33, 6, 29), - CABAC_ENTRY(175, 2, 62, 34, 0, 13, 43, 20, 33), - CABAC_ENTRY(176, 6, 46, 39, -18, 13, 36, 15, 30), - CABAC_ENTRY(177, 0, 54, 32, -12, 4, 47, 4, 45), - CABAC_ENTRY(178, 3, 54, 102, -94, 3, 55, 1, 58), - CABAC_ENTRY(179, 2, 58, 0, 0, 2, 58, 0, 62), - CABAC_ENTRY(180, 4, 63, 56, -15, 6, 60, 7, 61), - CABAC_ENTRY(181, 6, 51, 33, -4, 8, 44, 12, 38), - CABAC_ENTRY(182, 6, 57, 29, 10, 11, 44, 11, 45), - CABAC_ENTRY(183, 7, 53, 37, -5, 14, 42, 15, 39), - CABAC_ENTRY(184, 6, 52, 51, -29, 7, 48, 11, 42), - CABAC_ENTRY(185, 6, 55, 39, -9, 4, 56, 13, 44), - CABAC_ENTRY(186, 11, 45, 52, -34, 4, 52, 16, 45), - CABAC_ENTRY(187, 14, 36, 69, -58, 13, 37, 12, 41), - CABAC_ENTRY(188, 8, 53, 67, -63, 9, 49, 10, 49), - CABAC_ENTRY(189, -1, 82, 44, -5, 19, 58, 30, 34), - CABAC_ENTRY(190, 7, 55, 32, 7, 10, 48, 18, 42), - CABAC_ENTRY(191, -3, 78, 55, -29, 12, 45, 10, 55), - CABAC_ENTRY(192, 15, 46, 32, 1, 0, 69, 17, 51), - CABAC_ENTRY(193, 22, 31, 0, 0, 20, 33, 17, 46), - CABAC_ENTRY(194, -1, 84, 27, 36, 8, 63, 0, 89), - CABAC_ENTRY(195, 25, 7, 33, -25, 35, -18, 26, -19), - CABAC_ENTRY(196, 30, -7, 34, -30, 33, -25, 22, -17), - CABAC_ENTRY(197, 28, 3, 36, -28, 28, -3, 26, -17), - CABAC_ENTRY(198, 28, 4, 38, -28, 24, 10, 30, -25), - CABAC_ENTRY(199, 32, 0, 38, -27, 27, 0, 28, -20), - CABAC_ENTRY(200, 34, -1, 34, -18, 34, -14, 33, -23), - CABAC_ENTRY(201, 30, 6, 35, -16, 52, -44, 37, -27), - CABAC_ENTRY(202, 30, 6, 34, -14, 39, -24, 33, -23), - CABAC_ENTRY(203, 32, 9, 32, -8, 19, 17, 40, -28), - CABAC_ENTRY(204, 31, 19, 37, -6, 31, 25, 38, -17), - CABAC_ENTRY(205, 26, 27, 35, 0, 36, 29, 33, -11), - CABAC_ENTRY(206, 26, 30, 30, 10, 24, 33, 40, -15), - CABAC_ENTRY(207, 37, 20, 28, 18, 34, 15, 41, -6), - CABAC_ENTRY(208, 28, 34, 26, 25, 30, 20, 38, 1), - CABAC_ENTRY(209, 17, 70, 29, 41, 22, 73, 41, 17), - CABAC_ENTRY(210, 1, 67, 0, 75, 20, 34, 30, -6), - CABAC_ENTRY(211, 5, 59, 2, 72, 19, 31, 27, 3), - CABAC_ENTRY(212, 9, 67, 8, 77, 27, 44, 26, 22), - CABAC_ENTRY(213, 16, 30, 14, 35, 19, 16, 37, -16), - CABAC_ENTRY(214, 18, 32, 18, 31, 15, 36, 35, -4), - CABAC_ENTRY(215, 18, 35, 17, 35, 15, 36, 38, -8), - CABAC_ENTRY(216, 22, 29, 21, 30, 21, 28, 38, -3), - CABAC_ENTRY(217, 24, 31, 17, 45, 25, 21, 37, 3), - CABAC_ENTRY(218, 23, 38, 20, 42, 30, 20, 38, 5), - CABAC_ENTRY(219, 18, 43, 18, 45, 31, 12, 42, 0), - CABAC_ENTRY(220, 20, 41, 27, 26, 27, 16, 35, 16), - CABAC_ENTRY(221, 11, 63, 16, 54, 24, 42, 39, 22), - CABAC_ENTRY(222, 9, 59, 7, 66, 0, 93, 14, 48), - CABAC_ENTRY(223, 9, 64, 16, 56, 14, 56, 27, 37), - CABAC_ENTRY(224, -1, 94, 11, 73, 15, 57, 21, 60), - CABAC_ENTRY(225, -2, 89, 10, 67, 26, 38, 12, 68), - CABAC_ENTRY(226, -9, 108, -10, 116, -24, 127, 2, 97), - - /* Table 9-21 – Values of variables m and n for ctxIdx from 227 to 275 */ - CABAC_ENTRY(227, -6, 76, -23, 112, -24, 115, -3, 71), - CABAC_ENTRY(228, -2, 44, -15, 71, -22, 82, -6, 42), - CABAC_ENTRY(229, 0, 45, -7, 61, -9, 62, -5, 50), - CABAC_ENTRY(230, 0, 52, 0, 53, 0, 53, -3, 54), - CABAC_ENTRY(231, -3, 64, -5, 66, 0, 59, -2, 62), - CABAC_ENTRY(232, -2, 59, -11, 77, -14, 85, 0, 58), - CABAC_ENTRY(233, -4, 70, -9, 80, -13, 89, 1, 63), - CABAC_ENTRY(234, -4, 75, -9, 84, -13, 94, -2, 72), - CABAC_ENTRY(235, -8, 82, -10, 87, -11, 92, -1, 74), - CABAC_ENTRY(236, -17, 102, -34, 127, -29, 127, -9, 91), - CABAC_ENTRY(237, -9, 77, -21, 101, -21, 100, -5, 67), - CABAC_ENTRY(238, 3, 24, -3, 39, -14, 57, -5, 27), - CABAC_ENTRY(239, 0, 42, -5, 53, -12, 67, -3, 39), - CABAC_ENTRY(240, 0, 48, -7, 61, -11, 71, -2, 44), - CABAC_ENTRY(241, 0, 55, -11, 75, -10, 77, 0, 46), - CABAC_ENTRY(242, -6, 59, -15, 77, -21, 85, -16, 64), - CABAC_ENTRY(243, -7, 71, -17, 91, -16, 88, -8, 68), - CABAC_ENTRY(244, -12, 83, -25, 107, -23, 104, -10, 78), - CABAC_ENTRY(245, -11, 87, -25, 111, -15, 98, -6, 77), - CABAC_ENTRY(246, -30, 119, -28, 122, -37, 127, -10, 86), - CABAC_ENTRY(247, 1, 58, -11, 76, -10, 82, -12, 92), - CABAC_ENTRY(248, -3, 29, -10, 44, -8, 48, -15, 55), - CABAC_ENTRY(249, -1, 36, -10, 52, -8, 61, -10, 60), - CABAC_ENTRY(250, 1, 38, -10, 57, -8, 66, -6, 62), - CABAC_ENTRY(251, 2, 43, -9, 58, -7, 70, -4, 65), - CABAC_ENTRY(252, -6, 55, -16, 72, -14, 75, -12, 73), - CABAC_ENTRY(253, 0, 58, -7, 69, -10, 79, -8, 76), - CABAC_ENTRY(254, 0, 64, -4, 69, -9, 83, -7, 80), - CABAC_ENTRY(255, -3, 74, -5, 74, -12, 92, -9, 88), - CABAC_ENTRY(256, -10, 90, -9, 86, -18, 108, -17, 110), - CABAC_ENTRY(257, 0, 70, 2, 66, -4, 79, -11, 97), - CABAC_ENTRY(258, -4, 29, -9, 34, -22, 69, -20, 84), - CABAC_ENTRY(259, 5, 31, 1, 32, -16, 75, -11, 79), - CABAC_ENTRY(260, 7, 42, 11, 31, -2, 58, -6, 73), - CABAC_ENTRY(261, 1, 59, 5, 52, 1, 58, -4, 74), - CABAC_ENTRY(262, -2, 58, -2, 55, -13, 78, -13, 86), - CABAC_ENTRY(263, -3, 72, -2, 67, -9, 83, -13, 96), - CABAC_ENTRY(264, -3, 81, 0, 73, -4, 81, -11, 97), - CABAC_ENTRY(265, -11, 97, -8, 89, -13, 99, -19, 117), - CABAC_ENTRY(266, 0, 58, 3, 52, -13, 81, -8, 78), - CABAC_ENTRY(267, 8, 5, 7, 4, -6, 38, -5, 33), - CABAC_ENTRY(268, 10, 14, 10, 8, -13, 62, -4, 48), - CABAC_ENTRY(269, 14, 18, 17, 8, -6, 58, -2, 53), - CABAC_ENTRY(270, 13, 27, 16, 19, -2, 59, -3, 62), - CABAC_ENTRY(271, 2, 40, 3, 37, -16, 73, -13, 71), - CABAC_ENTRY(272, 0, 58, -1, 61, -10, 76, -10, 79), - CABAC_ENTRY(273, -3, 70, -5, 73, -13, 86, -12, 86), - CABAC_ENTRY(274, -6, 79, -1, 70, -9, 83, -13, 90), - CABAC_ENTRY(275, -8, 85, -4, 78, -10, 87, -14, 97), - - /* Table 9-22 – Values of variables m and n for ctxIdx from 277 to 337 */ - CABAC_ENTRY(277, -13, 106, -21, 126, -22, 127, -6, 93), - CABAC_ENTRY(278, -16, 106, -23, 124, -25, 127, -6, 84), - CABAC_ENTRY(279, -10, 87, -20, 110, -25, 120, -8, 79), - CABAC_ENTRY(280, -21, 114, -26, 126, -27, 127, 0, 66), - CABAC_ENTRY(281, -18, 110, -25, 124, -19, 114, -1, 71), - CABAC_ENTRY(282, -14, 98, -17, 105, -23, 117, 0, 62), - CABAC_ENTRY(283, -22, 110, -27, 121, -25, 118, -2, 60), - CABAC_ENTRY(284, -21, 106, -27, 117, -26, 117, -2, 59), - CABAC_ENTRY(285, -18, 103, -17, 102, -24, 113, -5, 75), - CABAC_ENTRY(286, -21, 107, -26, 117, -28, 118, -3, 62), - CABAC_ENTRY(287, -23, 108, -27, 116, -31, 120, -4, 58), - CABAC_ENTRY(288, -26, 112, -33, 122, -37, 124, -9, 66), - CABAC_ENTRY(289, -10, 96, -10, 95, -10, 94, -1, 79), - CABAC_ENTRY(290, -12, 95, -14, 100, -15, 102, 0, 71), - CABAC_ENTRY(291, -5, 91, -8, 95, -10, 99, 3, 68), - CABAC_ENTRY(292, -9, 93, -17, 111, -13, 106, 10, 44), - CABAC_ENTRY(293, -22, 94, -28, 114, -50, 127, -7, 62), - CABAC_ENTRY(294, -5, 86, -6, 89, -5, 92, 15, 36), - CABAC_ENTRY(295, 9, 67, -2, 80, 17, 57, 14, 40), - CABAC_ENTRY(296, -4, 80, -4, 82, -5, 86, 16, 27), - CABAC_ENTRY(297, -10, 85, -9, 85, -13, 94, 12, 29), - CABAC_ENTRY(298, -1, 70, -8, 81, -12, 91, 1, 44), - CABAC_ENTRY(299, 7, 60, -1, 72, -2, 77, 20, 36), - CABAC_ENTRY(300, 9, 58, 5, 64, 0, 71, 18, 32), - CABAC_ENTRY(301, 5, 61, 1, 67, -1, 73, 5, 42), - CABAC_ENTRY(302, 12, 50, 9, 56, 4, 64, 1, 48), - CABAC_ENTRY(303, 15, 50, 0, 69, -7, 81, 10, 62), - CABAC_ENTRY(304, 18, 49, 1, 69, 5, 64, 17, 46), - CABAC_ENTRY(305, 17, 54, 7, 69, 15, 57, 9, 64), - CABAC_ENTRY(306, 10, 41, -7, 69, 1, 67, -12, 104), - CABAC_ENTRY(307, 7, 46, -6, 67, 0, 68, -11, 97), - CABAC_ENTRY(308, -1, 51, -16, 77, -10, 67, -16, 96), - CABAC_ENTRY(309, 7, 49, -2, 64, 1, 68, -7, 88), - CABAC_ENTRY(310, 8, 52, 2, 61, 0, 77, -8, 85), - CABAC_ENTRY(311, 9, 41, -6, 67, 2, 64, -7, 85), - CABAC_ENTRY(312, 6, 47, -3, 64, 0, 68, -9, 85), - CABAC_ENTRY(313, 2, 55, 2, 57, -5, 78, -13, 88), - CABAC_ENTRY(314, 13, 41, -3, 65, 7, 55, 4, 66), - CABAC_ENTRY(315, 10, 44, -3, 66, 5, 59, -3, 77), - CABAC_ENTRY(316, 6, 50, 0, 62, 2, 65, -3, 76), - CABAC_ENTRY(317, 5, 53, 9, 51, 14, 54, -6, 76), - CABAC_ENTRY(318, 13, 49, -1, 66, 15, 44, 10, 58), - CABAC_ENTRY(319, 4, 63, -2, 71, 5, 60, -1, 76), - CABAC_ENTRY(320, 6, 64, -2, 75, 2, 70, -1, 83), - CABAC_ENTRY(321, -2, 69, -1, 70, -2, 76, -7, 99), - CABAC_ENTRY(322, -2, 59, -9, 72, -18, 86, -14, 95), - CABAC_ENTRY(323, 6, 70, 14, 60, 12, 70, 2, 95), - CABAC_ENTRY(324, 10, 44, 16, 37, 5, 64, 0, 76), - CABAC_ENTRY(325, 9, 31, 0, 47, -12, 70, -5, 74), - CABAC_ENTRY(326, 12, 43, 18, 35, 11, 55, 0, 70), - CABAC_ENTRY(327, 3, 53, 11, 37, 5, 56, -11, 75), - CABAC_ENTRY(328, 14, 34, 12, 41, 0, 69, 1, 68), - CABAC_ENTRY(329, 10, 38, 10, 41, 2, 65, 0, 65), - CABAC_ENTRY(330, -3, 52, 2, 48, -6, 74, -14, 73), - CABAC_ENTRY(331, 13, 40, 12, 41, 5, 54, 3, 62), - CABAC_ENTRY(332, 17, 32, 13, 41, 7, 54, 4, 62), - CABAC_ENTRY(333, 7, 44, 0, 59, -6, 76, -1, 68), - CABAC_ENTRY(334, 7, 38, 3, 50, -11, 82, -13, 75), - CABAC_ENTRY(335, 13, 50, 19, 40, -2, 77, 11, 55), - CABAC_ENTRY(336, 10, 57, 3, 66, -2, 77, 5, 64), - CABAC_ENTRY(337, 26, 43, 18, 50, 25, 42, 12, 70), - - /* Table 9-23 – Values of variables m and n for ctxIdx from 338 to 398 */ - CABAC_ENTRY(338, 14, 11, 19, -6, 17, -13, 15, 6), - CABAC_ENTRY(339, 11, 14, 18, -6, 16, -9, 6, 19), - CABAC_ENTRY(340, 9, 11, 14, 0, 17, -12, 7, 16), - CABAC_ENTRY(341, 18, 11, 26, -12, 27, -21, 12, 14), - CABAC_ENTRY(342, 21, 9, 31, -16, 37, -30, 18, 13), - CABAC_ENTRY(343, 23, -2, 33, -25, 41, -40, 13, 11), - CABAC_ENTRY(344, 32, -15, 33, -22, 42, -41, 13, 15), - CABAC_ENTRY(345, 32, -15, 37, -28, 48, -47, 15, 16), - CABAC_ENTRY(346, 34, -21, 39, -30, 39, -32, 12, 23), - CABAC_ENTRY(347, 39, -23, 42, -30, 46, -40, 13, 23), - CABAC_ENTRY(348, 42, -33, 47, -42, 52, -51, 15, 20), - CABAC_ENTRY(349, 41, -31, 45, -36, 46, -41, 14, 26), - CABAC_ENTRY(350, 46, -28, 49, -34, 52, -39, 14, 44), - CABAC_ENTRY(351, 38, -12, 41, -17, 43, -19, 17, 40), - CABAC_ENTRY(352, 21, 29, 32, 9, 32, 11, 17, 47), - CABAC_ENTRY(353, 45, -24, 69, -71, 61, -55, 24, 17), - CABAC_ENTRY(354, 53, -45, 63, -63, 56, -46, 21, 21), - CABAC_ENTRY(355, 48, -26, 66, -64, 62, -50, 25, 22), - CABAC_ENTRY(356, 65, -43, 77, -74, 81, -67, 31, 27), - CABAC_ENTRY(357, 43, -19, 54, -39, 45, -20, 22, 29), - CABAC_ENTRY(358, 39, -10, 52, -35, 35, -2, 19, 35), - CABAC_ENTRY(359, 30, 9, 41, -10, 28, 15, 14, 50), - CABAC_ENTRY(360, 18, 26, 36, 0, 34, 1, 10, 57), - CABAC_ENTRY(361, 20, 27, 40, -1, 39, 1, 7, 63), - CABAC_ENTRY(362, 0, 57, 30, 14, 30, 17, -2, 77), - CABAC_ENTRY(363, -14, 82, 28, 26, 20, 38, -4, 82), - CABAC_ENTRY(364, -5, 75, 23, 37, 18, 45, -3, 94), - CABAC_ENTRY(365, -19, 97, 12, 55, 15, 54, 9, 69), - CABAC_ENTRY(366, -35, 125, 11, 65, 0, 79, -12, 109), - CABAC_ENTRY(367, 27, 0, 37, -33, 36, -16, 36, -35), - CABAC_ENTRY(368, 28, 0, 39, -36, 37, -14, 36, -34), - CABAC_ENTRY(369, 31, -4, 40, -37, 37, -17, 32, -26), - CABAC_ENTRY(370, 27, 6, 38, -30, 32, 1, 37, -30), - CABAC_ENTRY(371, 34, 8, 46, -33, 34, 15, 44, -32), - CABAC_ENTRY(372, 30, 10, 42, -30, 29, 15, 34, -18), - CABAC_ENTRY(373, 24, 22, 40, -24, 24, 25, 34, -15), - CABAC_ENTRY(374, 33, 19, 49, -29, 34, 22, 40, -15), - CABAC_ENTRY(375, 22, 32, 38, -12, 31, 16, 33, -7), - CABAC_ENTRY(376, 26, 31, 40, -10, 35, 18, 35, -5), - CABAC_ENTRY(377, 21, 41, 38, -3, 31, 28, 33, 0), - CABAC_ENTRY(378, 26, 44, 46, -5, 33, 41, 38, 2), - CABAC_ENTRY(379, 23, 47, 31, 20, 36, 28, 33, 13), - CABAC_ENTRY(380, 16, 65, 29, 30, 27, 47, 23, 35), - CABAC_ENTRY(381, 14, 71, 25, 44, 21, 62, 13, 58), - CABAC_ENTRY(382, 8, 60, 12, 48, 18, 31, 29, -3), - CABAC_ENTRY(383, 6, 63, 11, 49, 19, 26, 26, 0), - CABAC_ENTRY(384, 17, 65, 26, 45, 36, 24, 22, 30), - CABAC_ENTRY(385, 21, 24, 22, 22, 24, 23, 31, -7), - CABAC_ENTRY(386, 23, 20, 23, 22, 27, 16, 35, -15), - CABAC_ENTRY(387, 26, 23, 27, 21, 24, 30, 34, -3), - CABAC_ENTRY(388, 27, 32, 33, 20, 31, 29, 34, 3), - CABAC_ENTRY(389, 28, 23, 26, 28, 22, 41, 36, -1), - CABAC_ENTRY(390, 28, 24, 30, 24, 22, 42, 34, 5), - CABAC_ENTRY(391, 23, 40, 27, 34, 16, 60, 32, 11), - CABAC_ENTRY(392, 24, 32, 18, 42, 15, 52, 35, 5), - CABAC_ENTRY(393, 28, 29, 25, 39, 14, 60, 34, 12), - CABAC_ENTRY(394, 23, 42, 18, 50, 3, 78, 39, 11), - CABAC_ENTRY(395, 19, 57, 12, 70, -16, 123, 30, 29), - CABAC_ENTRY(396, 22, 53, 21, 54, 21, 53, 34, 26), - CABAC_ENTRY(397, 22, 61, 14, 71, 22, 56, 29, 39), - CABAC_ENTRY(398, 11, 86, 11, 83, 25, 61, 19, 66), - - /* Values of variables m and n for ctxIdx from 399 to 463 (not documented) */ - CABAC_ENTRY(399, 12, 40, 25, 32, 21, 33, 31, 21), - CABAC_ENTRY(400, 11, 51, 21, 49, 19, 50, 31, 31), - CABAC_ENTRY(401, 14, 59, 21, 54, 17, 61, 25, 50), - CABAC_ENTRY(402, -4, 79, -5, 85, -3, 78, -17, 120), - CABAC_ENTRY(403, -7, 71, -6, 81, -8, 74, -20, 112), - CABAC_ENTRY(404, -5, 69, -10, 77, -9, 72, -18, 114), - CABAC_ENTRY(405, -9, 70, -7, 81, -10, 72, -11, 85), - CABAC_ENTRY(406, -8, 66, -17, 80, -18, 75, -15, 92), - CABAC_ENTRY(407, -10, 68, -18, 73, -12, 71, -14, 89), - CABAC_ENTRY(408, -19, 73, -4, 74, -11, 63, -26, 71), - CABAC_ENTRY(409, -12, 69, -10, 83, -5, 70, -15, 81), - CABAC_ENTRY(410, -16, 70, -9, 71, -17, 75, -14, 80), - CABAC_ENTRY(411, -15, 67, -9, 67, -14, 72, 0, 68), - CABAC_ENTRY(412, -20, 62, -1, 61, -16, 67, -14, 70), - CABAC_ENTRY(413, -19, 70, -8, 66, -8, 53, -24, 56), - CABAC_ENTRY(414, -16, 66, -14, 66, -14, 59, -23, 68), - CABAC_ENTRY(415, -22, 65, 0, 59, -9, 52, -24, 50), - CABAC_ENTRY(416, -20, 63, 2, 59, -11, 68, -11, 74), - CABAC_ENTRY(417, 9, -2, 17, -10, 9, -2, 23, -13), - CABAC_ENTRY(418, 26, -9, 32, -13, 30, -10, 26, -13), - CABAC_ENTRY(419, 33, -9, 42, -9, 31, -4, 40, -15), - CABAC_ENTRY(420, 39, -7, 49, -5, 33, -1, 49, -14), - CABAC_ENTRY(421, 41, -2, 53, 0, 33, 7, 44, 3), - CABAC_ENTRY(422, 45, 3, 64, 3, 31, 12, 45, 6), - CABAC_ENTRY(423, 49, 9, 68, 10, 37, 23, 44, 34), - CABAC_ENTRY(424, 45, 27, 66, 27, 31, 38, 33, 54), - CABAC_ENTRY(425, 36, 59, 47, 57, 20, 64, 19, 82), - CABAC_ENTRY(426, -6, 66, -5, 71, -9, 71, -3, 75), - CABAC_ENTRY(427, -7, 35, 0, 24, -7, 37, -1, 23), - CABAC_ENTRY(428, -7, 42, -1, 36, -8, 44, 1, 34), - CABAC_ENTRY(429, -8, 45, -2, 42, -11, 49, 1, 43), - CABAC_ENTRY(430, -5, 48, -2, 52, -10, 56, 0, 54), - CABAC_ENTRY(431, -12, 56, -9, 57, -12, 59, -2, 55), - CABAC_ENTRY(432, -6, 60, -6, 63, -8, 63, 0, 61), - CABAC_ENTRY(433, -5, 62, -4, 65, -9, 67, 1, 64), - CABAC_ENTRY(434, -8, 66, -4, 67, -6, 68, 0, 68), - CABAC_ENTRY(435, -8, 76, -7, 82, -10, 79, -9, 92), - CABAC_ENTRY(436, -5, 85, -3, 81, -3, 78, -14, 106), - CABAC_ENTRY(437, -6, 81, -3, 76, -8, 74, -13, 97), - CABAC_ENTRY(438, -10, 77, -7, 72, -9, 72, -15, 90), - CABAC_ENTRY(439, -7, 81, -6, 78, -10, 72, -12, 90), - CABAC_ENTRY(440, -17, 80, -12, 72, -18, 75, -18, 88), - CABAC_ENTRY(441, -18, 73, -14, 68, -12, 71, -10, 73), - CABAC_ENTRY(442, -4, 74, -3, 70, -11, 63, -9, 79), - CABAC_ENTRY(443, -10, 83, -6, 76, -5, 70, -14, 86), - CABAC_ENTRY(444, -9, 71, -5, 66, -17, 75, -10, 73), - CABAC_ENTRY(445, -9, 67, -5, 62, -14, 72, -10, 70), - CABAC_ENTRY(446, -1, 61, 0, 57, -16, 67, -10, 69), - CABAC_ENTRY(447, -8, 66, -4, 61, -8, 53, -5, 66), - CABAC_ENTRY(448, -14, 66, -9, 60, -14, 59, -9, 64), - CABAC_ENTRY(449, 0, 59, 1, 54, -9, 52, -5, 58), - CABAC_ENTRY(450, 2, 59, 2, 58, -11, 68, 2, 59), - CABAC_ENTRY(451, 21, -13, 17, -10, 9, -2, 21, -10), - CABAC_ENTRY(452, 33, -14, 32, -13, 30, -10, 24, -11), - CABAC_ENTRY(453, 39, -7, 42, -9, 31, -4, 28, -8), - CABAC_ENTRY(454, 46, -2, 49, -5, 33, -1, 28, -1), - CABAC_ENTRY(455, 51, 2, 53, 0, 33, 7, 29, 3), - CABAC_ENTRY(456, 60, 6, 64, 3, 31, 12, 29, 9), - CABAC_ENTRY(457, 61, 17, 68, 10, 37, 23, 35, 20), - CABAC_ENTRY(458, 55, 34, 66, 27, 31, 38, 29, 36), - CABAC_ENTRY(459, 42, 62, 47, 57, 20, 64, 14, 67), -}; - -static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value) -{ - u8 bit = field.offset % 32, word = field.offset / 32; - u64 mask = GENMASK_ULL(bit + field.len - 1, bit); - u64 val = ((u64)value << bit) & mask; - - buf[word] &= ~mask; - buf[word] |= val; - if (bit + field.len > 32) { - buf[word + 1] &= ~(mask >> 32); - buf[word + 1] |= val >> 32; - } -} - -static void assemble_hw_pps(struct rkvdec_ctx *ctx, - struct rkvdec_h264_run *run) -{ - struct rkvdec_h264_ctx *h264_ctx = ctx->priv; - const struct v4l2_ctrl_h264_sps *sps = run->sps; - const struct v4l2_ctrl_h264_pps *pps = run->pps; - const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params; - const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb; - struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu; - struct rkvdec_sps_pps_packet *hw_ps; - dma_addr_t scaling_list_address; - u32 scaling_distance; - u32 i; - - /* - * HW read the SPS/PPS information from PPS packet index by PPS id. - * offset from the base can be calculated by PPS_id * 32 (size per PPS - * packet unit). so the driver copy SPS/PPS information to the exact PPS - * packet unit for HW accessing. - */ - hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id]; - memset(hw_ps, 0, sizeof(*hw_ps)); - -#define WRITE_PPS(value, field) set_ps_field(hw_ps->info, field, value) - /* write sps */ - WRITE_PPS(sps->seq_parameter_set_id, SEQ_PARAMETER_SET_ID); - WRITE_PPS(sps->profile_idc, PROFILE_IDC); - WRITE_PPS(!!(sps->constraint_set_flags & (1 << 3)), CONSTRAINT_SET3_FLAG); - WRITE_PPS(sps->chroma_format_idc, CHROMA_FORMAT_IDC); - WRITE_PPS(sps->bit_depth_luma_minus8, BIT_DEPTH_LUMA); - WRITE_PPS(sps->bit_depth_chroma_minus8, BIT_DEPTH_CHROMA); - WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS), - QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG); - WRITE_PPS(sps->log2_max_frame_num_minus4, LOG2_MAX_FRAME_NUM_MINUS4); - WRITE_PPS(sps->max_num_ref_frames, MAX_NUM_REF_FRAMES); - WRITE_PPS(sps->pic_order_cnt_type, PIC_ORDER_CNT_TYPE); - WRITE_PPS(sps->log2_max_pic_order_cnt_lsb_minus4, - LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4); - WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO), - DELTA_PIC_ORDER_ALWAYS_ZERO_FLAG); - - /* - * Use the SPS values since they are already in macroblocks - * dimensions, height can be field height (halved) if - * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is not set and also it allows - * decoding smaller images into larger allocation which can be used - * to implementing SVC spatial layer support. - */ - WRITE_PPS(sps->pic_width_in_mbs_minus1 + 1, PIC_WIDTH_IN_MBS); - WRITE_PPS(sps->pic_height_in_map_units_minus1 + 1, PIC_HEIGHT_IN_MBS); - - WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY), - FRAME_MBS_ONLY_FLAG); - WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD), - MB_ADAPTIVE_FRAME_FIELD_FLAG); - WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE), - DIRECT_8X8_INFERENCE_FLAG); - - /* write pps */ - WRITE_PPS(pps->pic_parameter_set_id, PIC_PARAMETER_SET_ID); - WRITE_PPS(pps->seq_parameter_set_id, PPS_SEQ_PARAMETER_SET_ID); - WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE), - ENTROPY_CODING_MODE_FLAG); - WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT), - BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT_FLAG); - WRITE_PPS(pps->num_ref_idx_l0_default_active_minus1, - NUM_REF_IDX_L_DEFAULT_ACTIVE_MINUS1(0)); - WRITE_PPS(pps->num_ref_idx_l1_default_active_minus1, - NUM_REF_IDX_L_DEFAULT_ACTIVE_MINUS1(1)); - WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED), - WEIGHTED_PRED_FLAG); - WRITE_PPS(pps->weighted_bipred_idc, WEIGHTED_BIPRED_IDC); - WRITE_PPS(pps->pic_init_qp_minus26, PIC_INIT_QP_MINUS26); - WRITE_PPS(pps->pic_init_qs_minus26, PIC_INIT_QS_MINUS26); - WRITE_PPS(pps->chroma_qp_index_offset, CHROMA_QP_INDEX_OFFSET); - WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT), - DEBLOCKING_FILTER_CONTROL_PRESENT_FLAG); - WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED), - CONSTRAINED_INTRA_PRED_FLAG); - WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT), - REDUNDANT_PIC_CNT_PRESENT); - WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE), - TRANSFORM_8X8_MODE_FLAG); - WRITE_PPS(pps->second_chroma_qp_index_offset, - SECOND_CHROMA_QP_INDEX_OFFSET); - - WRITE_PPS(!!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT), - SCALING_LIST_ENABLE_FLAG); - /* To be on the safe side, program the scaling matrix address */ - scaling_distance = offsetof(struct rkvdec_h264_priv_tbl, scaling_list); - scaling_list_address = h264_ctx->priv_tbl.dma + scaling_distance; - WRITE_PPS(scaling_list_address, SCALING_LIST_ADDRESS); - - for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { - u32 is_longterm = 0; - - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - is_longterm = 1; - - WRITE_PPS(is_longterm, IS_LONG_TERM(i)); - } -} - -static void lookup_ref_buf_idx(struct rkvdec_ctx *ctx, - struct rkvdec_h264_run *run) -{ - const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params; - u32 i; - - for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { - struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; - const struct v4l2_h264_dpb_entry *dpb = run->decode_params->dpb; - struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; - struct vb2_buffer *buf = NULL; - - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) { - buf = vb2_find_buffer(cap_q, dpb[i].reference_ts); - if (!buf) - pr_debug("No buffer for reference_ts %llu", - dpb[i].reference_ts); - } - - run->ref_buf[i] = buf; - } -} - -static void assemble_hw_rps(struct rkvdec_ctx *ctx, - struct v4l2_h264_reflist_builder *builder, - struct rkvdec_h264_run *run) -{ - const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params; - const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb; - struct rkvdec_h264_ctx *h264_ctx = ctx->priv; - struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu; - - u32 *hw_rps = priv_tbl->rps; - u32 i, j; - u16 *p = (u16 *)hw_rps; - - memset(hw_rps, 0, sizeof(priv_tbl->rps)); - - /* - * Assign an invalid pic_num if DPB entry at that position is inactive. - * If we assign 0 in that position hardware will treat that as a real - * reference picture with pic_num 0, triggering output picture - * corruption. - */ - for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { - if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) - continue; - - p[i] = builder->refs[i].frame_num; - } - - for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { - for (i = 0; i < builder->num_valid; i++) { - struct v4l2_h264_reference *ref; - bool dpb_valid; - bool bottom; - - switch (j) { - case 0: - ref = &h264_ctx->reflists.p[i]; - break; - case 1: - ref = &h264_ctx->reflists.b0[i]; - break; - case 2: - ref = &h264_ctx->reflists.b1[i]; - break; - } - - if (WARN_ON(ref->index >= ARRAY_SIZE(dec_params->dpb))) - continue; - - dpb_valid = run->ref_buf[ref->index] != NULL; - bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF; - - set_ps_field(hw_rps, DPB_INFO(i, j), - ref->index | dpb_valid << 4); - set_ps_field(hw_rps, BOTTOM_FLAG(i, j), bottom); - } - } -} - -static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx, - struct rkvdec_h264_run *run) -{ - const struct v4l2_ctrl_h264_scaling_matrix *scaling = run->scaling_matrix; - const struct v4l2_ctrl_h264_pps *pps = run->pps; - struct rkvdec_h264_ctx *h264_ctx = ctx->priv; - struct rkvdec_h264_priv_tbl *tbl = h264_ctx->priv_tbl.cpu; - - if (!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT)) - return; - - BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_4x4) != - sizeof(scaling->scaling_list_4x4)); - BUILD_BUG_ON(sizeof(tbl->scaling_list.scaling_list_8x8) != - sizeof(scaling->scaling_list_8x8)); - - memcpy(tbl->scaling_list.scaling_list_4x4, - scaling->scaling_list_4x4, - sizeof(scaling->scaling_list_4x4)); - - memcpy(tbl->scaling_list.scaling_list_8x8, - scaling->scaling_list_8x8, - sizeof(scaling->scaling_list_8x8)); -} - -/* - * dpb poc related registers table - */ -static const u32 poc_reg_tbl_top_field[16] = { - RKVDEC_REG_H264_POC_REFER0(0), - RKVDEC_REG_H264_POC_REFER0(2), - RKVDEC_REG_H264_POC_REFER0(4), - RKVDEC_REG_H264_POC_REFER0(6), - RKVDEC_REG_H264_POC_REFER0(8), - RKVDEC_REG_H264_POC_REFER0(10), - RKVDEC_REG_H264_POC_REFER0(12), - RKVDEC_REG_H264_POC_REFER0(14), - RKVDEC_REG_H264_POC_REFER1(1), - RKVDEC_REG_H264_POC_REFER1(3), - RKVDEC_REG_H264_POC_REFER1(5), - RKVDEC_REG_H264_POC_REFER1(7), - RKVDEC_REG_H264_POC_REFER1(9), - RKVDEC_REG_H264_POC_REFER1(11), - RKVDEC_REG_H264_POC_REFER1(13), - RKVDEC_REG_H264_POC_REFER2(0) -}; - -static const u32 poc_reg_tbl_bottom_field[16] = { - RKVDEC_REG_H264_POC_REFER0(1), - RKVDEC_REG_H264_POC_REFER0(3), - RKVDEC_REG_H264_POC_REFER0(5), - RKVDEC_REG_H264_POC_REFER0(7), - RKVDEC_REG_H264_POC_REFER0(9), - RKVDEC_REG_H264_POC_REFER0(11), - RKVDEC_REG_H264_POC_REFER0(13), - RKVDEC_REG_H264_POC_REFER1(0), - RKVDEC_REG_H264_POC_REFER1(2), - RKVDEC_REG_H264_POC_REFER1(4), - RKVDEC_REG_H264_POC_REFER1(6), - RKVDEC_REG_H264_POC_REFER1(8), - RKVDEC_REG_H264_POC_REFER1(10), - RKVDEC_REG_H264_POC_REFER1(12), - RKVDEC_REG_H264_POC_REFER1(14), - RKVDEC_REG_H264_POC_REFER2(1) -}; - -static void config_registers(struct rkvdec_ctx *ctx, - struct rkvdec_h264_run *run) -{ - struct rkvdec_dev *rkvdec = ctx->dev; - const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params; - const struct v4l2_ctrl_h264_sps *sps = run->sps; - const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb; - struct rkvdec_h264_ctx *h264_ctx = ctx->priv; - dma_addr_t priv_start_addr = h264_ctx->priv_tbl.dma; - const struct v4l2_pix_format_mplane *dst_fmt; - struct vb2_v4l2_buffer *src_buf = run->base.bufs.src; - struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst; - const struct v4l2_format *f; - dma_addr_t rlc_addr; - dma_addr_t refer_addr; - u32 rlc_len; - u32 hor_virstride; - u32 ver_virstride; - u32 y_virstride; - u32 yuv_virstride = 0; - u32 offset; - dma_addr_t dst_addr; - u32 reg, i; - - reg = RKVDEC_MODE(RKVDEC_MODE_H264); - writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL); - - f = &ctx->decoded_fmt; - dst_fmt = &f->fmt.pix_mp; - hor_virstride = dst_fmt->plane_fmt[0].bytesperline; - ver_virstride = dst_fmt->height; - y_virstride = hor_virstride * ver_virstride; - - if (sps->chroma_format_idc == 0) - yuv_virstride = y_virstride; - else if (sps->chroma_format_idc == 1) - yuv_virstride = y_virstride + y_virstride / 2; - else if (sps->chroma_format_idc == 2) - yuv_virstride = 2 * y_virstride; - - reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) | - RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) | - RKVDEC_SLICE_NUM_HIGHBIT | - RKVDEC_SLICE_NUM_LOWBITS(0x7ff); - writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR); - - /* config rlc base address */ - rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); - writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE); - writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_RLCWRITE_BASE); - - rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0); - reg = RKVDEC_STRM_LEN(rlc_len); - writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN); - - /* config cabac table */ - offset = offsetof(struct rkvdec_h264_priv_tbl, cabac_table); - writel_relaxed(priv_start_addr + offset, - rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE); - - /* config output base address */ - dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); - writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE); - - reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16); - writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE); - - reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16); - writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE); - - /* config ref pic address & poc */ - for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { - struct vb2_buffer *vb_buf = run->ref_buf[i]; - - /* - * If a DPB entry is unused or invalid, address of current destination - * buffer is returned. - */ - if (!vb_buf) - vb_buf = &dst_buf->vb2_buf; - refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0); - - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - refer_addr |= RKVDEC_COLMV_USED_FLAG_REF; - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD) - refer_addr |= RKVDEC_FIELD_REF; - - if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF) - refer_addr |= RKVDEC_TOPFIELD_USED_REF; - if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF) - refer_addr |= RKVDEC_BOTFIELD_USED_REF; - - writel_relaxed(dpb[i].top_field_order_cnt, - rkvdec->regs + poc_reg_tbl_top_field[i]); - writel_relaxed(dpb[i].bottom_field_order_cnt, - rkvdec->regs + poc_reg_tbl_bottom_field[i]); - - if (i < V4L2_H264_NUM_DPB_ENTRIES - 1) - writel_relaxed(refer_addr, - rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i)); - else - writel_relaxed(refer_addr, - rkvdec->regs + RKVDEC_REG_H264_BASE_REFER15); - } - - reg = RKVDEC_CUR_POC(dec_params->top_field_order_cnt); - writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0); - - reg = RKVDEC_CUR_POC(dec_params->bottom_field_order_cnt); - writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC1); - - /* config hw pps address */ - offset = offsetof(struct rkvdec_h264_priv_tbl, param_set); - writel_relaxed(priv_start_addr + offset, - rkvdec->regs + RKVDEC_REG_PPS_BASE); - - /* config hw rps address */ - offset = offsetof(struct rkvdec_h264_priv_tbl, rps); - writel_relaxed(priv_start_addr + offset, - rkvdec->regs + RKVDEC_REG_RPS_BASE); - - reg = RKVDEC_AXI_DDR_RDATA(0); - writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA); - - reg = RKVDEC_AXI_DDR_WDATA(0); - writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA); - - offset = offsetof(struct rkvdec_h264_priv_tbl, err_info); - writel_relaxed(priv_start_addr + offset, - rkvdec->regs + RKVDEC_REG_H264_ERRINFO_BASE); -} - -#define RKVDEC_H264_MAX_DEPTH_IN_BYTES 2 - -static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp; - - fmt->num_planes = 1; - if (!fmt->plane_fmt[0].sizeimage) - fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * - RKVDEC_H264_MAX_DEPTH_IN_BYTES; - return 0; -} - -static enum rkvdec_image_fmt rkvdec_h264_get_image_fmt(struct rkvdec_ctx *ctx, - struct v4l2_ctrl *ctrl) -{ - const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; - - if (ctrl->id != V4L2_CID_STATELESS_H264_SPS) - return RKVDEC_IMG_FMT_ANY; - - if (sps->bit_depth_luma_minus8 == 0) { - if (sps->chroma_format_idc == 2) - return RKVDEC_IMG_FMT_422_8BIT; - else - return RKVDEC_IMG_FMT_420_8BIT; - } else if (sps->bit_depth_luma_minus8 == 2) { - if (sps->chroma_format_idc == 2) - return RKVDEC_IMG_FMT_422_10BIT; - else - return RKVDEC_IMG_FMT_420_10BIT; - } - - return RKVDEC_IMG_FMT_ANY; -} - -static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx, - const struct v4l2_ctrl_h264_sps *sps) -{ - unsigned int width, height; - - if (sps->chroma_format_idc > 2) - /* Only 4:0:0, 4:2:0 and 4:2:2 are supported */ - return -EINVAL; - if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) - /* Luma and chroma bit depth mismatch */ - return -EINVAL; - if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2) - /* Only 8-bit and 10-bit is supported */ - return -EINVAL; - - width = (sps->pic_width_in_mbs_minus1 + 1) * 16; - height = (sps->pic_height_in_map_units_minus1 + 1) * 16; - - /* - * When frame_mbs_only_flag is not set, this is field height, - * which is half the final height (see (7-18) in the - * specification) - */ - if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)) - height *= 2; - - if (width > ctx->coded_fmt.fmt.pix_mp.width || - height > ctx->coded_fmt.fmt.pix_mp.height) - return -EINVAL; - - return 0; -} - -static int rkvdec_h264_start(struct rkvdec_ctx *ctx) -{ - struct rkvdec_dev *rkvdec = ctx->dev; - struct rkvdec_h264_priv_tbl *priv_tbl; - struct rkvdec_h264_ctx *h264_ctx; - struct v4l2_ctrl *ctrl; - int ret; - - ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, - V4L2_CID_STATELESS_H264_SPS); - if (!ctrl) - return -EINVAL; - - ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps); - if (ret) - return ret; - - h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL); - if (!h264_ctx) - return -ENOMEM; - - priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), - &h264_ctx->priv_tbl.dma, GFP_KERNEL); - if (!priv_tbl) { - ret = -ENOMEM; - goto err_free_ctx; - } - - h264_ctx->priv_tbl.size = sizeof(*priv_tbl); - h264_ctx->priv_tbl.cpu = priv_tbl; - memcpy(priv_tbl->cabac_table, rkvdec_h264_cabac_table, - sizeof(rkvdec_h264_cabac_table)); - - ctx->priv = h264_ctx; - return 0; - -err_free_ctx: - kfree(h264_ctx); - return ret; -} - -static void rkvdec_h264_stop(struct rkvdec_ctx *ctx) -{ - struct rkvdec_h264_ctx *h264_ctx = ctx->priv; - struct rkvdec_dev *rkvdec = ctx->dev; - - dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size, - h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma); - kfree(h264_ctx); -} - -static void rkvdec_h264_run_preamble(struct rkvdec_ctx *ctx, - struct rkvdec_h264_run *run) -{ - struct v4l2_ctrl *ctrl; - - ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, - V4L2_CID_STATELESS_H264_DECODE_PARAMS); - run->decode_params = ctrl ? ctrl->p_cur.p : NULL; - ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, - V4L2_CID_STATELESS_H264_SPS); - run->sps = ctrl ? ctrl->p_cur.p : NULL; - ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, - V4L2_CID_STATELESS_H264_PPS); - run->pps = ctrl ? ctrl->p_cur.p : NULL; - ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, - V4L2_CID_STATELESS_H264_SCALING_MATRIX); - run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL; - - rkvdec_run_preamble(ctx, &run->base); -} - -static int rkvdec_h264_run(struct rkvdec_ctx *ctx) -{ - struct v4l2_h264_reflist_builder reflist_builder; - struct rkvdec_dev *rkvdec = ctx->dev; - struct rkvdec_h264_ctx *h264_ctx = ctx->priv; - struct rkvdec_h264_run run; - - rkvdec_h264_run_preamble(ctx, &run); - - /* Build the P/B{0,1} ref lists. */ - v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params, - run.sps, run.decode_params->dpb); - v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p); - v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0, - h264_ctx->reflists.b1); - - assemble_hw_scaling_list(ctx, &run); - assemble_hw_pps(ctx, &run); - lookup_ref_buf_idx(ctx, &run); - assemble_hw_rps(ctx, &reflist_builder, &run); - config_registers(ctx, &run); - - rkvdec_run_postamble(ctx, &run.base); - - schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000)); - - writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN); - writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E); - writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); - writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); - - /* Start decoding! */ - writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E | - RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E, - rkvdec->regs + RKVDEC_REG_INTERRUPT); - - return 0; -} - -static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) -{ - if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) - return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps); - - return 0; -} - -const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops = { - .adjust_fmt = rkvdec_h264_adjust_fmt, - .start = rkvdec_h264_start, - .stop = rkvdec_h264_stop, - .run = rkvdec_h264_run, - .try_ctrl = rkvdec_h264_try_ctrl, - .get_image_fmt = rkvdec_h264_get_image_fmt, -}; diff --git a/drivers/staging/media/rkvdec/rkvdec-regs.h b/drivers/staging/media/rkvdec/rkvdec-regs.h deleted file mode 100644 index 15b9bee92016c..0000000000000 --- a/drivers/staging/media/rkvdec/rkvdec-regs.h +++ /dev/null @@ -1,223 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#ifndef RKVDEC_REGS_H_ -#define RKVDEC_REGS_H_ - -/* rkvcodec registers */ -#define RKVDEC_REG_INTERRUPT 0x004 -#define RKVDEC_INTERRUPT_DEC_E BIT(0) -#define RKVDEC_CONFIG_DEC_CLK_GATE_E BIT(1) -#define RKVDEC_E_STRMD_CLKGATE_DIS BIT(2) -#define RKVDEC_TIMEOUT_MODE BIT(3) -#define RKVDEC_IRQ_DIS BIT(4) -#define RKVDEC_TIMEOUT_E BIT(5) -#define RKVDEC_BUF_EMPTY_E BIT(6) -#define RKVDEC_STRM_E_WAITDECFIFO_EMPTY BIT(7) -#define RKVDEC_IRQ BIT(8) -#define RKVDEC_IRQ_RAW BIT(9) -#define RKVDEC_E_REWRITE_VALID BIT(10) -#define RKVDEC_COMMONIRQ_MODE BIT(11) -#define RKVDEC_RDY_STA BIT(12) -#define RKVDEC_BUS_STA BIT(13) -#define RKVDEC_ERR_STA BIT(14) -#define RKVDEC_TIMEOUT_STA BIT(15) -#define RKVDEC_BUF_EMPTY_STA BIT(16) -#define RKVDEC_COLMV_REF_ERR_STA BIT(17) -#define RKVDEC_CABU_END_STA BIT(18) -#define RKVDEC_H264ORVP9_ERR_MODE BIT(19) -#define RKVDEC_SOFTRST_EN_P BIT(20) -#define RKVDEC_FORCE_SOFTRESET_VALID BIT(21) -#define RKVDEC_SOFTRESET_RDY BIT(22) - -#define RKVDEC_REG_SYSCTRL 0x008 -#define RKVDEC_IN_ENDIAN BIT(0) -#define RKVDEC_IN_SWAP32_E BIT(1) -#define RKVDEC_IN_SWAP64_E BIT(2) -#define RKVDEC_STR_ENDIAN BIT(3) -#define RKVDEC_STR_SWAP32_E BIT(4) -#define RKVDEC_STR_SWAP64_E BIT(5) -#define RKVDEC_OUT_ENDIAN BIT(6) -#define RKVDEC_OUT_SWAP32_E BIT(7) -#define RKVDEC_OUT_CBCR_SWAP BIT(8) -#define RKVDEC_RLC_MODE_DIRECT_WRITE BIT(10) -#define RKVDEC_RLC_MODE BIT(11) -#define RKVDEC_STRM_START_BIT(x) (((x) & 0x7f) << 12) -#define RKVDEC_MODE(x) (((x) & 0x03) << 20) -#define RKVDEC_MODE_H264 1 -#define RKVDEC_MODE_VP9 2 -#define RKVDEC_RPS_MODE BIT(24) -#define RKVDEC_STRM_MODE BIT(25) -#define RKVDEC_H264_STRM_LASTPKT BIT(26) -#define RKVDEC_H264_FIRSTSLICE_FLAG BIT(27) -#define RKVDEC_H264_FRAME_ORSLICE BIT(28) -#define RKVDEC_BUSPR_SLOT_DIS BIT(29) - -#define RKVDEC_REG_PICPAR 0x00C -#define RKVDEC_Y_HOR_VIRSTRIDE(x) ((x) & 0x1ff) -#define RKVDEC_SLICE_NUM_HIGHBIT BIT(11) -#define RKVDEC_UV_HOR_VIRSTRIDE(x) (((x) & 0x1ff) << 12) -#define RKVDEC_SLICE_NUM_LOWBITS(x) (((x) & 0x7ff) << 21) - -#define RKVDEC_REG_STRM_RLC_BASE 0x010 - -#define RKVDEC_REG_STRM_LEN 0x014 -#define RKVDEC_STRM_LEN(x) ((x) & 0x7ffffff) - -#define RKVDEC_REG_CABACTBL_PROB_BASE 0x018 -#define RKVDEC_REG_DECOUT_BASE 0x01C - -#define RKVDEC_REG_Y_VIRSTRIDE 0x020 -#define RKVDEC_Y_VIRSTRIDE(x) ((x) & 0xfffff) - -#define RKVDEC_REG_YUV_VIRSTRIDE 0x024 -#define RKVDEC_YUV_VIRSTRIDE(x) ((x) & 0x1fffff) -#define RKVDEC_REG_H264_BASE_REFER(i) (((i) * 0x04) + 0x028) - -#define RKVDEC_REG_H264_BASE_REFER15 0x0C0 -#define RKVDEC_FIELD_REF BIT(0) -#define RKVDEC_TOPFIELD_USED_REF BIT(1) -#define RKVDEC_BOTFIELD_USED_REF BIT(2) -#define RKVDEC_COLMV_USED_FLAG_REF BIT(3) - -#define RKVDEC_REG_VP9_LAST_FRAME_BASE 0x02c -#define RKVDEC_REG_VP9_GOLDEN_FRAME_BASE 0x030 -#define RKVDEC_REG_VP9_ALTREF_FRAME_BASE 0x034 - -#define RKVDEC_REG_VP9_CPRHEADER_OFFSET 0x028 -#define RKVDEC_VP9_CPRHEADER_OFFSET(x) ((x) & 0xffff) - -#define RKVDEC_REG_VP9_REFERLAST_BASE 0x02C -#define RKVDEC_REG_VP9_REFERGOLDEN_BASE 0x030 -#define RKVDEC_REG_VP9_REFERALFTER_BASE 0x034 - -#define RKVDEC_REG_VP9COUNT_BASE 0x038 -#define RKVDEC_VP9COUNT_UPDATE_EN BIT(0) - -#define RKVDEC_REG_VP9_SEGIDLAST_BASE 0x03C -#define RKVDEC_REG_VP9_SEGIDCUR_BASE 0x040 -#define RKVDEC_REG_VP9_FRAME_SIZE(i) ((i) * 0x04 + 0x044) -#define RKVDEC_VP9_FRAMEWIDTH(x) (((x) & 0xffff) << 0) -#define RKVDEC_VP9_FRAMEHEIGHT(x) (((x) & 0xffff) << 16) - -#define RKVDEC_VP9_SEGID_GRP(i) ((i) * 0x04 + 0x050) -#define RKVDEC_SEGID_ABS_DELTA(x) ((x) & 0x1) -#define RKVDEC_SEGID_FRAME_QP_DELTA_EN(x) (((x) & 0x1) << 1) -#define RKVDEC_SEGID_FRAME_QP_DELTA(x) (((x) & 0x1ff) << 2) -#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(x) (((x) & 0x1) << 11) -#define RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(x) (((x) & 0x7f) << 12) -#define RKVDEC_SEGID_REFERINFO_EN(x) (((x) & 0x1) << 19) -#define RKVDEC_SEGID_REFERINFO(x) (((x) & 0x03) << 20) -#define RKVDEC_SEGID_FRAME_SKIP_EN(x) (((x) & 0x1) << 22) - -#define RKVDEC_VP9_CPRHEADER_CONFIG 0x070 -#define RKVDEC_VP9_TX_MODE(x) ((x) & 0x07) -#define RKVDEC_VP9_FRAME_REF_MODE(x) (((x) & 0x03) << 3) - -#define RKVDEC_VP9_REF_SCALE(i) ((i) * 0x04 + 0x074) -#define RKVDEC_VP9_REF_HOR_SCALE(x) ((x) & 0xffff) -#define RKVDEC_VP9_REF_VER_SCALE(x) (((x) & 0xffff) << 16) - -#define RKVDEC_VP9_REF_DELTAS_LASTFRAME 0x080 -#define RKVDEC_REF_DELTAS_LASTFRAME(pos, val) (((val) & 0x7f) << ((pos) * 7)) - -#define RKVDEC_VP9_INFO_LASTFRAME 0x084 -#define RKVDEC_MODE_DELTAS_LASTFRAME(pos, val) (((val) & 0x7f) << ((pos) * 7)) -#define RKVDEC_SEG_EN_LASTFRAME BIT(16) -#define RKVDEC_LAST_SHOW_FRAME BIT(17) -#define RKVDEC_LAST_INTRA_ONLY BIT(18) -#define RKVDEC_LAST_WIDHHEIGHT_EQCUR BIT(19) -#define RKVDEC_COLOR_SPACE_LASTKEYFRAME(x) (((x) & 0x07) << 20) - -#define RKVDEC_VP9_INTERCMD_BASE 0x088 - -#define RKVDEC_VP9_INTERCMD_NUM 0x08C -#define RKVDEC_INTERCMD_NUM(x) ((x) & 0xffffff) - -#define RKVDEC_VP9_LASTTILE_SIZE 0x090 -#define RKVDEC_LASTTILE_SIZE(x) ((x) & 0xffffff) - -#define RKVDEC_VP9_HOR_VIRSTRIDE(i) ((i) * 0x04 + 0x094) -#define RKVDEC_HOR_Y_VIRSTRIDE(x) ((x) & 0x1ff) -#define RKVDEC_HOR_UV_VIRSTRIDE(x) (((x) & 0x1ff) << 16) - -#define RKVDEC_REG_H264_POC_REFER0(i) (((i) * 0x04) + 0x064) -#define RKVDEC_REG_H264_POC_REFER1(i) (((i) * 0x04) + 0x0C4) -#define RKVDEC_REG_H264_POC_REFER2(i) (((i) * 0x04) + 0x120) -#define RKVDEC_POC_REFER(x) ((x) & 0xffffffff) - -#define RKVDEC_REG_CUR_POC0 0x0A0 -#define RKVDEC_REG_CUR_POC1 0x128 -#define RKVDEC_CUR_POC(x) ((x) & 0xffffffff) - -#define RKVDEC_REG_RLCWRITE_BASE 0x0A4 -#define RKVDEC_REG_PPS_BASE 0x0A8 -#define RKVDEC_REG_RPS_BASE 0x0AC - -#define RKVDEC_REG_STRMD_ERR_EN 0x0B0 -#define RKVDEC_STRMD_ERR_EN(x) ((x) & 0xffffffff) - -#define RKVDEC_REG_STRMD_ERR_STA 0x0B4 -#define RKVDEC_STRMD_ERR_STA(x) ((x) & 0xfffffff) -#define RKVDEC_COLMV_ERR_REF_PICIDX(x) (((x) & 0x0f) << 28) - -#define RKVDEC_REG_STRMD_ERR_CTU 0x0B8 -#define RKVDEC_STRMD_ERR_CTU(x) ((x) & 0xff) -#define RKVDEC_STRMD_ERR_CTU_YOFFSET(x) (((x) & 0xff) << 8) -#define RKVDEC_STRMFIFO_SPACE2FULL(x) (((x) & 0x7f) << 16) -#define RKVDEC_VP9_ERR_EN_CTU0 BIT(24) - -#define RKVDEC_REG_SAO_CTU_POS 0x0BC -#define RKVDEC_SAOWR_XOFFSET(x) ((x) & 0x1ff) -#define RKVDEC_SAOWR_YOFFSET(x) (((x) & 0x3ff) << 16) - -#define RKVDEC_VP9_LAST_FRAME_YSTRIDE 0x0C0 -#define RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE 0x0C4 -#define RKVDEC_VP9_ALTREF_FRAME_YSTRIDE 0x0C8 -#define RKVDEC_VP9_REF_YSTRIDE(x) (((x) & 0xfffff) << 0) - -#define RKVDEC_VP9_LAST_FRAME_YUVSTRIDE 0x0CC -#define RKVDEC_VP9_REF_YUVSTRIDE(x) (((x) & 0x1fffff) << 0) - -#define RKVDEC_VP9_REF_COLMV_BASE 0x0D0 - -#define RKVDEC_REG_PERFORMANCE_CYCLE 0x100 -#define RKVDEC_PERFORMANCE_CYCLE(x) ((x) & 0xffffffff) - -#define RKVDEC_REG_AXI_DDR_RDATA 0x104 -#define RKVDEC_AXI_DDR_RDATA(x) ((x) & 0xffffffff) - -#define RKVDEC_REG_AXI_DDR_WDATA 0x108 -#define RKVDEC_AXI_DDR_WDATA(x) ((x) & 0xffffffff) - -#define RKVDEC_REG_FPGADEBUG_RESET 0x10C -#define RKVDEC_BUSIFD_RESETN BIT(0) -#define RKVDEC_CABAC_RESETN BIT(1) -#define RKVDEC_DEC_CTRL_RESETN BIT(2) -#define RKVDEC_TRANSD_RESETN BIT(3) -#define RKVDEC_INTRA_RESETN BIT(4) -#define RKVDEC_INTER_RESETN BIT(5) -#define RKVDEC_RECON_RESETN BIT(6) -#define RKVDEC_FILER_RESETN BIT(7) - -#define RKVDEC_REG_PERFORMANCE_SEL 0x110 -#define RKVDEC_PERF_SEL_CNT0(x) ((x) & 0x3f) -#define RKVDEC_PERF_SEL_CNT1(x) (((x) & 0x3f) << 8) -#define RKVDEC_PERF_SEL_CNT2(x) (((x) & 0x3f) << 16) - -#define RKVDEC_REG_PERFORMANCE_CNT(i) ((i) * 0x04 + 0x114) -#define RKVDEC_PERF_CNT(x) ((x) & 0xffffffff) - -#define RKVDEC_REG_H264_ERRINFO_BASE 0x12C - -#define RKVDEC_REG_H264_ERRINFO_NUM 0x130 -#define RKVDEC_SLICEDEC_NUM(x) ((x) & 0x3fff) -#define RKVDEC_STRMD_DECT_ERR_FLAG BIT(15) -#define RKVDEC_ERR_PKT_NUM(x) (((x) & 0x3fff) << 16) - -#define RKVDEC_REG_H264_ERR_E 0x134 -#define RKVDEC_H264_ERR_EN_HIGHBITS(x) ((x) & 0x3fffffff) - -#define RKVDEC_REG_PREF_LUMA_CACHE_COMMAND 0x410 -#define RKVDEC_REG_PREF_CHR_CACHE_COMMAND 0x450 - -#endif /* RKVDEC_REGS_H_ */ diff --git a/drivers/staging/media/rkvdec/rkvdec-vp9.c b/drivers/staging/media/rkvdec/rkvdec-vp9.c deleted file mode 100644 index 0e7e16f20eeb0..0000000000000 --- a/drivers/staging/media/rkvdec/rkvdec-vp9.c +++ /dev/null @@ -1,1072 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip Video Decoder VP9 backend - * - * Copyright (C) 2019 Collabora, Ltd. - * Boris Brezillon <boris.brezillon@collabora.com> - * Copyright (C) 2021 Collabora, Ltd. - * Andrzej Pietrasiewicz <andrzej.p@collabora.com> - * - * Copyright (C) 2016 Rockchip Electronics Co., Ltd. - * Alpha Lin <Alpha.Lin@rock-chips.com> - */ - -/* - * For following the vp9 spec please start reading this driver - * code from rkvdec_vp9_run() followed by rkvdec_vp9_done(). - */ - -#include <linux/kernel.h> -#include <linux/vmalloc.h> -#include <media/v4l2-mem2mem.h> -#include <media/v4l2-vp9.h> - -#include "rkvdec.h" -#include "rkvdec-regs.h" - -#define RKVDEC_VP9_PROBE_SIZE 4864 -#define RKVDEC_VP9_COUNT_SIZE 13232 -#define RKVDEC_VP9_MAX_SEGMAP_SIZE 73728 - -struct rkvdec_vp9_intra_mode_probs { - u8 y_mode[105]; - u8 uv_mode[23]; -}; - -struct rkvdec_vp9_intra_only_frame_probs { - u8 coef_intra[4][2][128]; - struct rkvdec_vp9_intra_mode_probs intra_mode[10]; -}; - -struct rkvdec_vp9_inter_frame_probs { - u8 y_mode[4][9]; - u8 comp_mode[5]; - u8 comp_ref[5]; - u8 single_ref[5][2]; - u8 inter_mode[7][3]; - u8 interp_filter[4][2]; - u8 padding0[11]; - u8 coef[2][4][2][128]; - u8 uv_mode_0_2[3][9]; - u8 padding1[5]; - u8 uv_mode_3_5[3][9]; - u8 padding2[5]; - u8 uv_mode_6_8[3][9]; - u8 padding3[5]; - u8 uv_mode_9[9]; - u8 padding4[7]; - u8 padding5[16]; - struct { - u8 joint[3]; - u8 sign[2]; - u8 classes[2][10]; - u8 class0_bit[2]; - u8 bits[2][10]; - u8 class0_fr[2][2][3]; - u8 fr[2][3]; - u8 class0_hp[2]; - u8 hp[2]; - } mv; -}; - -struct rkvdec_vp9_probs { - u8 partition[16][3]; - u8 pred[3]; - u8 tree[7]; - u8 skip[3]; - u8 tx32[2][3]; - u8 tx16[2][2]; - u8 tx8[2][1]; - u8 is_inter[4]; - /* 128 bit alignment */ - u8 padding0[3]; - union { - struct rkvdec_vp9_inter_frame_probs inter; - struct rkvdec_vp9_intra_only_frame_probs intra_only; - }; - /* 128 bit alignment */ - u8 padding1[11]; -}; - -/* Data structure describing auxiliary buffer format. */ -struct rkvdec_vp9_priv_tbl { - struct rkvdec_vp9_probs probs; - u8 segmap[2][RKVDEC_VP9_MAX_SEGMAP_SIZE]; -}; - -struct rkvdec_vp9_refs_counts { - u32 eob[2]; - u32 coeff[3]; -}; - -struct rkvdec_vp9_inter_frame_symbol_counts { - u32 partition[16][4]; - u32 skip[3][2]; - u32 inter[4][2]; - u32 tx32p[2][4]; - u32 tx16p[2][4]; - u32 tx8p[2][2]; - u32 y_mode[4][10]; - u32 uv_mode[10][10]; - u32 comp[5][2]; - u32 comp_ref[5][2]; - u32 single_ref[5][2][2]; - u32 mv_mode[7][4]; - u32 filter[4][3]; - u32 mv_joint[4]; - u32 sign[2][2]; - /* add 1 element for align */ - u32 classes[2][11 + 1]; - u32 class0[2][2]; - u32 bits[2][10][2]; - u32 class0_fp[2][2][4]; - u32 fp[2][4]; - u32 class0_hp[2][2]; - u32 hp[2][2]; - struct rkvdec_vp9_refs_counts ref_cnt[2][4][2][6][6]; -}; - -struct rkvdec_vp9_intra_frame_symbol_counts { - u32 partition[4][4][4]; - u32 skip[3][2]; - u32 intra[4][2]; - u32 tx32p[2][4]; - u32 tx16p[2][4]; - u32 tx8p[2][2]; - struct rkvdec_vp9_refs_counts ref_cnt[2][4][2][6][6]; -}; - -struct rkvdec_vp9_run { - struct rkvdec_run base; - const struct v4l2_ctrl_vp9_frame *decode_params; -}; - -struct rkvdec_vp9_frame_info { - u32 valid : 1; - u32 segmapid : 1; - u32 frame_context_idx : 2; - u32 reference_mode : 2; - u32 tx_mode : 3; - u32 interpolation_filter : 3; - u32 flags; - u64 timestamp; - struct v4l2_vp9_segmentation seg; - struct v4l2_vp9_loop_filter lf; -}; - -struct rkvdec_vp9_ctx { - struct rkvdec_aux_buf priv_tbl; - struct rkvdec_aux_buf count_tbl; - struct v4l2_vp9_frame_symbol_counts inter_cnts; - struct v4l2_vp9_frame_symbol_counts intra_cnts; - struct v4l2_vp9_frame_context probability_tables; - struct v4l2_vp9_frame_context frame_context[4]; - struct rkvdec_vp9_frame_info cur; - struct rkvdec_vp9_frame_info last; -}; - -static void write_coeff_plane(const u8 coef[6][6][3], u8 *coeff_plane) -{ - unsigned int idx = 0, byte_count = 0; - int k, m, n; - u8 p; - - for (k = 0; k < 6; k++) { - for (m = 0; m < 6; m++) { - for (n = 0; n < 3; n++) { - p = coef[k][m][n]; - coeff_plane[idx++] = p; - byte_count++; - if (byte_count == 27) { - idx += 5; - byte_count = 0; - } - } - } - } -} - -static void init_intra_only_probs(struct rkvdec_ctx *ctx, - const struct rkvdec_vp9_run *run) -{ - struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; - struct rkvdec_vp9_priv_tbl *tbl = vp9_ctx->priv_tbl.cpu; - struct rkvdec_vp9_intra_only_frame_probs *rkprobs; - const struct v4l2_vp9_frame_context *probs; - unsigned int i, j, k; - - rkprobs = &tbl->probs.intra_only; - probs = &vp9_ctx->probability_tables; - - /* - * intra only 149 x 128 bits ,aligned to 152 x 128 bits coeff related - * prob 64 x 128 bits - */ - for (i = 0; i < ARRAY_SIZE(probs->coef); i++) { - for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++) - write_coeff_plane(probs->coef[i][j][0], - rkprobs->coef_intra[i][j]); - } - - /* intra mode prob 80 x 128 bits */ - for (i = 0; i < ARRAY_SIZE(v4l2_vp9_kf_y_mode_prob); i++) { - unsigned int byte_count = 0; - int idx = 0; - - /* vp9_kf_y_mode_prob */ - for (j = 0; j < ARRAY_SIZE(v4l2_vp9_kf_y_mode_prob[0]); j++) { - for (k = 0; k < ARRAY_SIZE(v4l2_vp9_kf_y_mode_prob[0][0]); - k++) { - u8 val = v4l2_vp9_kf_y_mode_prob[i][j][k]; - - rkprobs->intra_mode[i].y_mode[idx++] = val; - byte_count++; - if (byte_count == 27) { - byte_count = 0; - idx += 5; - } - } - } - } - - for (i = 0; i < sizeof(v4l2_vp9_kf_uv_mode_prob); ++i) { - const u8 *ptr = (const u8 *)v4l2_vp9_kf_uv_mode_prob; - - rkprobs->intra_mode[i / 23].uv_mode[i % 23] = ptr[i]; - } -} - -static void init_inter_probs(struct rkvdec_ctx *ctx, - const struct rkvdec_vp9_run *run) -{ - struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; - struct rkvdec_vp9_priv_tbl *tbl = vp9_ctx->priv_tbl.cpu; - struct rkvdec_vp9_inter_frame_probs *rkprobs; - const struct v4l2_vp9_frame_context *probs; - unsigned int i, j, k; - - rkprobs = &tbl->probs.inter; - probs = &vp9_ctx->probability_tables; - - /* - * inter probs - * 151 x 128 bits, aligned to 152 x 128 bits - * inter only - * intra_y_mode & inter_block info 6 x 128 bits - */ - - memcpy(rkprobs->y_mode, probs->y_mode, sizeof(rkprobs->y_mode)); - memcpy(rkprobs->comp_mode, probs->comp_mode, - sizeof(rkprobs->comp_mode)); - memcpy(rkprobs->comp_ref, probs->comp_ref, - sizeof(rkprobs->comp_ref)); - memcpy(rkprobs->single_ref, probs->single_ref, - sizeof(rkprobs->single_ref)); - memcpy(rkprobs->inter_mode, probs->inter_mode, - sizeof(rkprobs->inter_mode)); - memcpy(rkprobs->interp_filter, probs->interp_filter, - sizeof(rkprobs->interp_filter)); - - /* 128 x 128 bits coeff related */ - for (i = 0; i < ARRAY_SIZE(probs->coef); i++) { - for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++) { - for (k = 0; k < ARRAY_SIZE(probs->coef[0][0]); k++) - write_coeff_plane(probs->coef[i][j][k], - rkprobs->coef[k][i][j]); - } - } - - /* intra uv mode 6 x 128 */ - memcpy(rkprobs->uv_mode_0_2, &probs->uv_mode[0], - sizeof(rkprobs->uv_mode_0_2)); - memcpy(rkprobs->uv_mode_3_5, &probs->uv_mode[3], - sizeof(rkprobs->uv_mode_3_5)); - memcpy(rkprobs->uv_mode_6_8, &probs->uv_mode[6], - sizeof(rkprobs->uv_mode_6_8)); - memcpy(rkprobs->uv_mode_9, &probs->uv_mode[9], - sizeof(rkprobs->uv_mode_9)); - - /* mv related 6 x 128 */ - memcpy(rkprobs->mv.joint, probs->mv.joint, - sizeof(rkprobs->mv.joint)); - memcpy(rkprobs->mv.sign, probs->mv.sign, - sizeof(rkprobs->mv.sign)); - memcpy(rkprobs->mv.classes, probs->mv.classes, - sizeof(rkprobs->mv.classes)); - memcpy(rkprobs->mv.class0_bit, probs->mv.class0_bit, - sizeof(rkprobs->mv.class0_bit)); - memcpy(rkprobs->mv.bits, probs->mv.bits, - sizeof(rkprobs->mv.bits)); - memcpy(rkprobs->mv.class0_fr, probs->mv.class0_fr, - sizeof(rkprobs->mv.class0_fr)); - memcpy(rkprobs->mv.fr, probs->mv.fr, - sizeof(rkprobs->mv.fr)); - memcpy(rkprobs->mv.class0_hp, probs->mv.class0_hp, - sizeof(rkprobs->mv.class0_hp)); - memcpy(rkprobs->mv.hp, probs->mv.hp, - sizeof(rkprobs->mv.hp)); -} - -static void init_probs(struct rkvdec_ctx *ctx, - const struct rkvdec_vp9_run *run) -{ - const struct v4l2_ctrl_vp9_frame *dec_params; - struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; - struct rkvdec_vp9_priv_tbl *tbl = vp9_ctx->priv_tbl.cpu; - struct rkvdec_vp9_probs *rkprobs = &tbl->probs; - const struct v4l2_vp9_segmentation *seg; - const struct v4l2_vp9_frame_context *probs; - bool intra_only; - - dec_params = run->decode_params; - probs = &vp9_ctx->probability_tables; - seg = &dec_params->seg; - - memset(rkprobs, 0, sizeof(*rkprobs)); - - intra_only = !!(dec_params->flags & - (V4L2_VP9_FRAME_FLAG_KEY_FRAME | - V4L2_VP9_FRAME_FLAG_INTRA_ONLY)); - - /* sb info 5 x 128 bit */ - memcpy(rkprobs->partition, - intra_only ? v4l2_vp9_kf_partition_probs : probs->partition, - sizeof(rkprobs->partition)); - - memcpy(rkprobs->pred, seg->pred_probs, sizeof(rkprobs->pred)); - memcpy(rkprobs->tree, seg->tree_probs, sizeof(rkprobs->tree)); - memcpy(rkprobs->skip, probs->skip, sizeof(rkprobs->skip)); - memcpy(rkprobs->tx32, probs->tx32, sizeof(rkprobs->tx32)); - memcpy(rkprobs->tx16, probs->tx16, sizeof(rkprobs->tx16)); - memcpy(rkprobs->tx8, probs->tx8, sizeof(rkprobs->tx8)); - memcpy(rkprobs->is_inter, probs->is_inter, sizeof(rkprobs->is_inter)); - - if (intra_only) - init_intra_only_probs(ctx, run); - else - init_inter_probs(ctx, run); -} - -struct rkvdec_vp9_ref_reg { - u32 reg_frm_size; - u32 reg_hor_stride; - u32 reg_y_stride; - u32 reg_yuv_stride; - u32 reg_ref_base; -}; - -static struct rkvdec_vp9_ref_reg ref_regs[] = { - { - .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(0), - .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(0), - .reg_y_stride = RKVDEC_VP9_LAST_FRAME_YSTRIDE, - .reg_yuv_stride = RKVDEC_VP9_LAST_FRAME_YUVSTRIDE, - .reg_ref_base = RKVDEC_REG_VP9_LAST_FRAME_BASE, - }, - { - .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(1), - .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(1), - .reg_y_stride = RKVDEC_VP9_GOLDEN_FRAME_YSTRIDE, - .reg_yuv_stride = 0, - .reg_ref_base = RKVDEC_REG_VP9_GOLDEN_FRAME_BASE, - }, - { - .reg_frm_size = RKVDEC_REG_VP9_FRAME_SIZE(2), - .reg_hor_stride = RKVDEC_VP9_HOR_VIRSTRIDE(2), - .reg_y_stride = RKVDEC_VP9_ALTREF_FRAME_YSTRIDE, - .reg_yuv_stride = 0, - .reg_ref_base = RKVDEC_REG_VP9_ALTREF_FRAME_BASE, - } -}; - -static struct rkvdec_decoded_buffer * -get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp) -{ - struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; - struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; - struct vb2_buffer *buf; - - /* - * If a ref is unused or invalid, address of current destination - * buffer is returned. - */ - buf = vb2_find_buffer(cap_q, timestamp); - if (!buf) - buf = &dst->vb2_buf; - - return vb2_to_rkvdec_decoded_buf(buf); -} - -static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf) -{ - unsigned int aligned_pitch, aligned_height, yuv_len; - - aligned_height = round_up(buf->vp9.height, 64); - aligned_pitch = round_up(buf->vp9.width * buf->vp9.bit_depth, 512) / 8; - yuv_len = (aligned_height * aligned_pitch * 3) / 2; - - return vb2_dma_contig_plane_dma_addr(&buf->base.vb.vb2_buf, 0) + - yuv_len; -} - -static void config_ref_registers(struct rkvdec_ctx *ctx, - const struct rkvdec_vp9_run *run, - struct rkvdec_decoded_buffer *ref_buf, - struct rkvdec_vp9_ref_reg *ref_reg) -{ - unsigned int aligned_pitch, aligned_height, y_len, yuv_len; - struct rkvdec_dev *rkvdec = ctx->dev; - - aligned_height = round_up(ref_buf->vp9.height, 64); - writel_relaxed(RKVDEC_VP9_FRAMEWIDTH(ref_buf->vp9.width) | - RKVDEC_VP9_FRAMEHEIGHT(ref_buf->vp9.height), - rkvdec->regs + ref_reg->reg_frm_size); - - writel_relaxed(vb2_dma_contig_plane_dma_addr(&ref_buf->base.vb.vb2_buf, 0), - rkvdec->regs + ref_reg->reg_ref_base); - - if (&ref_buf->base.vb == run->base.bufs.dst) - return; - - aligned_pitch = round_up(ref_buf->vp9.width * ref_buf->vp9.bit_depth, 512) / 8; - y_len = aligned_height * aligned_pitch; - yuv_len = (y_len * 3) / 2; - - writel_relaxed(RKVDEC_HOR_Y_VIRSTRIDE(aligned_pitch / 16) | - RKVDEC_HOR_UV_VIRSTRIDE(aligned_pitch / 16), - rkvdec->regs + ref_reg->reg_hor_stride); - writel_relaxed(RKVDEC_VP9_REF_YSTRIDE(y_len / 16), - rkvdec->regs + ref_reg->reg_y_stride); - - if (!ref_reg->reg_yuv_stride) - return; - - writel_relaxed(RKVDEC_VP9_REF_YUVSTRIDE(yuv_len / 16), - rkvdec->regs + ref_reg->reg_yuv_stride); -} - -static void config_seg_registers(struct rkvdec_ctx *ctx, unsigned int segid) -{ - struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; - const struct v4l2_vp9_segmentation *seg; - struct rkvdec_dev *rkvdec = ctx->dev; - s16 feature_val; - int feature_id; - u32 val = 0; - - seg = vp9_ctx->last.valid ? &vp9_ctx->last.seg : &vp9_ctx->cur.seg; - feature_id = V4L2_VP9_SEG_LVL_ALT_Q; - if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) { - feature_val = seg->feature_data[segid][feature_id]; - val |= RKVDEC_SEGID_FRAME_QP_DELTA_EN(1) | - RKVDEC_SEGID_FRAME_QP_DELTA(feature_val); - } - - feature_id = V4L2_VP9_SEG_LVL_ALT_L; - if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) { - feature_val = seg->feature_data[segid][feature_id]; - val |= RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE_EN(1) | - RKVDEC_SEGID_FRAME_LOOPFILTER_VALUE(feature_val); - } - - feature_id = V4L2_VP9_SEG_LVL_REF_FRAME; - if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) { - feature_val = seg->feature_data[segid][feature_id]; - val |= RKVDEC_SEGID_REFERINFO_EN(1) | - RKVDEC_SEGID_REFERINFO(feature_val); - } - - feature_id = V4L2_VP9_SEG_LVL_SKIP; - if (v4l2_vp9_seg_feat_enabled(seg->feature_enabled, feature_id, segid)) - val |= RKVDEC_SEGID_FRAME_SKIP_EN(1); - - if (!segid && - (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE)) - val |= RKVDEC_SEGID_ABS_DELTA(1); - - writel_relaxed(val, rkvdec->regs + RKVDEC_VP9_SEGID_GRP(segid)); -} - -static void update_dec_buf_info(struct rkvdec_decoded_buffer *buf, - const struct v4l2_ctrl_vp9_frame *dec_params) -{ - buf->vp9.width = dec_params->frame_width_minus_1 + 1; - buf->vp9.height = dec_params->frame_height_minus_1 + 1; - buf->vp9.bit_depth = dec_params->bit_depth; -} - -static void update_ctx_cur_info(struct rkvdec_vp9_ctx *vp9_ctx, - struct rkvdec_decoded_buffer *buf, - const struct v4l2_ctrl_vp9_frame *dec_params) -{ - vp9_ctx->cur.valid = true; - vp9_ctx->cur.reference_mode = dec_params->reference_mode; - vp9_ctx->cur.interpolation_filter = dec_params->interpolation_filter; - vp9_ctx->cur.flags = dec_params->flags; - vp9_ctx->cur.timestamp = buf->base.vb.vb2_buf.timestamp; - vp9_ctx->cur.seg = dec_params->seg; - vp9_ctx->cur.lf = dec_params->lf; -} - -static void update_ctx_last_info(struct rkvdec_vp9_ctx *vp9_ctx) -{ - vp9_ctx->last = vp9_ctx->cur; -} - -static void config_registers(struct rkvdec_ctx *ctx, - const struct rkvdec_vp9_run *run) -{ - unsigned int y_len, uv_len, yuv_len, bit_depth, aligned_height, aligned_pitch, stream_len; - const struct v4l2_ctrl_vp9_frame *dec_params; - struct rkvdec_decoded_buffer *ref_bufs[3]; - struct rkvdec_decoded_buffer *dst, *last, *mv_ref; - struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; - u32 val, last_frame_info = 0; - const struct v4l2_vp9_segmentation *seg; - struct rkvdec_dev *rkvdec = ctx->dev; - dma_addr_t addr; - bool intra_only; - unsigned int i; - - dec_params = run->decode_params; - dst = vb2_to_rkvdec_decoded_buf(&run->base.bufs.dst->vb2_buf); - ref_bufs[0] = get_ref_buf(ctx, &dst->base.vb, dec_params->last_frame_ts); - ref_bufs[1] = get_ref_buf(ctx, &dst->base.vb, dec_params->golden_frame_ts); - ref_bufs[2] = get_ref_buf(ctx, &dst->base.vb, dec_params->alt_frame_ts); - - if (vp9_ctx->last.valid) - last = get_ref_buf(ctx, &dst->base.vb, vp9_ctx->last.timestamp); - else - last = dst; - - update_dec_buf_info(dst, dec_params); - update_ctx_cur_info(vp9_ctx, dst, dec_params); - seg = &dec_params->seg; - - intra_only = !!(dec_params->flags & - (V4L2_VP9_FRAME_FLAG_KEY_FRAME | - V4L2_VP9_FRAME_FLAG_INTRA_ONLY)); - - writel_relaxed(RKVDEC_MODE(RKVDEC_MODE_VP9), - rkvdec->regs + RKVDEC_REG_SYSCTRL); - - bit_depth = dec_params->bit_depth; - aligned_height = round_up(ctx->decoded_fmt.fmt.pix_mp.height, 64); - - aligned_pitch = round_up(ctx->decoded_fmt.fmt.pix_mp.width * - bit_depth, - 512) / 8; - y_len = aligned_height * aligned_pitch; - uv_len = y_len / 2; - yuv_len = y_len + uv_len; - - writel_relaxed(RKVDEC_Y_HOR_VIRSTRIDE(aligned_pitch / 16) | - RKVDEC_UV_HOR_VIRSTRIDE(aligned_pitch / 16), - rkvdec->regs + RKVDEC_REG_PICPAR); - writel_relaxed(RKVDEC_Y_VIRSTRIDE(y_len / 16), - rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE); - writel_relaxed(RKVDEC_YUV_VIRSTRIDE(yuv_len / 16), - rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE); - - stream_len = vb2_get_plane_payload(&run->base.bufs.src->vb2_buf, 0); - writel_relaxed(RKVDEC_STRM_LEN(stream_len), - rkvdec->regs + RKVDEC_REG_STRM_LEN); - - /* - * Reset count buffer, because decoder only output intra related syntax - * counts when decoding intra frame, but update entropy need to update - * all the probabilities. - */ - if (intra_only) - memset(vp9_ctx->count_tbl.cpu, 0, vp9_ctx->count_tbl.size); - - vp9_ctx->cur.segmapid = vp9_ctx->last.segmapid; - if (!intra_only && - !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) && - (!(seg->flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED) || - (seg->flags & V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP))) - vp9_ctx->cur.segmapid++; - - for (i = 0; i < ARRAY_SIZE(ref_bufs); i++) - config_ref_registers(ctx, run, ref_bufs[i], &ref_regs[i]); - - for (i = 0; i < 8; i++) - config_seg_registers(ctx, i); - - writel_relaxed(RKVDEC_VP9_TX_MODE(vp9_ctx->cur.tx_mode) | - RKVDEC_VP9_FRAME_REF_MODE(dec_params->reference_mode), - rkvdec->regs + RKVDEC_VP9_CPRHEADER_CONFIG); - - if (!intra_only) { - const struct v4l2_vp9_loop_filter *lf; - s8 delta; - - if (vp9_ctx->last.valid) - lf = &vp9_ctx->last.lf; - else - lf = &vp9_ctx->cur.lf; - - val = 0; - for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) { - delta = lf->ref_deltas[i]; - val |= RKVDEC_REF_DELTAS_LASTFRAME(i, delta); - } - - writel_relaxed(val, - rkvdec->regs + RKVDEC_VP9_REF_DELTAS_LASTFRAME); - - for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) { - delta = lf->mode_deltas[i]; - last_frame_info |= RKVDEC_MODE_DELTAS_LASTFRAME(i, - delta); - } - } - - if (vp9_ctx->last.valid && !intra_only && - vp9_ctx->last.seg.flags & V4L2_VP9_SEGMENTATION_FLAG_ENABLED) - last_frame_info |= RKVDEC_SEG_EN_LASTFRAME; - - if (vp9_ctx->last.valid && - vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_SHOW_FRAME) - last_frame_info |= RKVDEC_LAST_SHOW_FRAME; - - if (vp9_ctx->last.valid && - vp9_ctx->last.flags & - (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY)) - last_frame_info |= RKVDEC_LAST_INTRA_ONLY; - - if (vp9_ctx->last.valid && - last->vp9.width == dst->vp9.width && - last->vp9.height == dst->vp9.height) - last_frame_info |= RKVDEC_LAST_WIDHHEIGHT_EQCUR; - - writel_relaxed(last_frame_info, - rkvdec->regs + RKVDEC_VP9_INFO_LASTFRAME); - - writel_relaxed(stream_len - dec_params->compressed_header_size - - dec_params->uncompressed_header_size, - rkvdec->regs + RKVDEC_VP9_LASTTILE_SIZE); - - for (i = 0; !intra_only && i < ARRAY_SIZE(ref_bufs); i++) { - unsigned int refw = ref_bufs[i]->vp9.width; - unsigned int refh = ref_bufs[i]->vp9.height; - u32 hscale, vscale; - - hscale = (refw << 14) / dst->vp9.width; - vscale = (refh << 14) / dst->vp9.height; - writel_relaxed(RKVDEC_VP9_REF_HOR_SCALE(hscale) | - RKVDEC_VP9_REF_VER_SCALE(vscale), - rkvdec->regs + RKVDEC_VP9_REF_SCALE(i)); - } - - addr = vb2_dma_contig_plane_dma_addr(&dst->base.vb.vb2_buf, 0); - writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE); - addr = vb2_dma_contig_plane_dma_addr(&run->base.bufs.src->vb2_buf, 0); - writel_relaxed(addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE); - writel_relaxed(vp9_ctx->priv_tbl.dma + - offsetof(struct rkvdec_vp9_priv_tbl, probs), - rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE); - writel_relaxed(vp9_ctx->count_tbl.dma, - rkvdec->regs + RKVDEC_REG_VP9COUNT_BASE); - - writel_relaxed(vp9_ctx->priv_tbl.dma + - offsetof(struct rkvdec_vp9_priv_tbl, segmap) + - (RKVDEC_VP9_MAX_SEGMAP_SIZE * vp9_ctx->cur.segmapid), - rkvdec->regs + RKVDEC_REG_VP9_SEGIDCUR_BASE); - writel_relaxed(vp9_ctx->priv_tbl.dma + - offsetof(struct rkvdec_vp9_priv_tbl, segmap) + - (RKVDEC_VP9_MAX_SEGMAP_SIZE * (!vp9_ctx->cur.segmapid)), - rkvdec->regs + RKVDEC_REG_VP9_SEGIDLAST_BASE); - - if (!intra_only && - !(dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) && - vp9_ctx->last.valid) - mv_ref = last; - else - mv_ref = dst; - - writel_relaxed(get_mv_base_addr(mv_ref), - rkvdec->regs + RKVDEC_VP9_REF_COLMV_BASE); - - writel_relaxed(ctx->decoded_fmt.fmt.pix_mp.width | - (ctx->decoded_fmt.fmt.pix_mp.height << 16), - rkvdec->regs + RKVDEC_REG_PERFORMANCE_CYCLE); -} - -static int validate_dec_params(struct rkvdec_ctx *ctx, - const struct v4l2_ctrl_vp9_frame *dec_params) -{ - unsigned int aligned_width, aligned_height; - - /* We only support profile 0. */ - if (dec_params->profile != 0) { - dev_err(ctx->dev->dev, "unsupported profile %d\n", - dec_params->profile); - return -EINVAL; - } - - aligned_width = round_up(dec_params->frame_width_minus_1 + 1, 64); - aligned_height = round_up(dec_params->frame_height_minus_1 + 1, 64); - - /* - * Userspace should update the capture/decoded format when the - * resolution changes. - */ - if (aligned_width != ctx->decoded_fmt.fmt.pix_mp.width || - aligned_height != ctx->decoded_fmt.fmt.pix_mp.height) { - dev_err(ctx->dev->dev, - "unexpected bitstream resolution %dx%d\n", - dec_params->frame_width_minus_1 + 1, - dec_params->frame_height_minus_1 + 1); - return -EINVAL; - } - - return 0; -} - -static int rkvdec_vp9_run_preamble(struct rkvdec_ctx *ctx, - struct rkvdec_vp9_run *run) -{ - const struct v4l2_ctrl_vp9_frame *dec_params; - const struct v4l2_ctrl_vp9_compressed_hdr *prob_updates; - struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; - struct v4l2_ctrl *ctrl; - unsigned int fctx_idx; - int ret; - - /* v4l2-specific stuff */ - rkvdec_run_preamble(ctx, &run->base); - - ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, - V4L2_CID_STATELESS_VP9_FRAME); - if (WARN_ON(!ctrl)) - return -EINVAL; - dec_params = ctrl->p_cur.p; - - ret = validate_dec_params(ctx, dec_params); - if (ret) - return ret; - - run->decode_params = dec_params; - - ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_VP9_COMPRESSED_HDR); - if (WARN_ON(!ctrl)) - return -EINVAL; - prob_updates = ctrl->p_cur.p; - vp9_ctx->cur.tx_mode = prob_updates->tx_mode; - - /* - * vp9 stuff - * - * by this point the userspace has done all parts of 6.2 uncompressed_header() - * except this fragment: - * if ( FrameIsIntra || error_resilient_mode ) { - * setup_past_independence ( ) - * if ( frame_type == KEY_FRAME || error_resilient_mode == 1 || - * reset_frame_context == 3 ) { - * for ( i = 0; i < 4; i ++ ) { - * save_probs( i ) - * } - * } else if ( reset_frame_context == 2 ) { - * save_probs( frame_context_idx ) - * } - * frame_context_idx = 0 - * } - */ - fctx_idx = v4l2_vp9_reset_frame_ctx(dec_params, vp9_ctx->frame_context); - vp9_ctx->cur.frame_context_idx = fctx_idx; - - /* 6.1 frame(sz): load_probs() and load_probs2() */ - vp9_ctx->probability_tables = vp9_ctx->frame_context[fctx_idx]; - - /* - * The userspace has also performed 6.3 compressed_header(), but handling the - * probs in a special way. All probs which need updating, except MV-related, - * have been read from the bitstream and translated through inv_map_table[], - * but no 6.3.6 inv_recenter_nonneg(v, m) has been performed. The values passed - * by userspace are either translated values (there are no 0 values in - * inv_map_table[]), or zero to indicate no update. All MV-related probs which need - * updating have been read from the bitstream and (mv_prob << 1) | 1 has been - * performed. The values passed by userspace are either new values - * to replace old ones (the above mentioned shift and bitwise or never result in - * a zero) or zero to indicate no update. - * fw_update_probs() performs actual probs updates or leaves probs as-is - * for values for which a zero was passed from userspace. - */ - v4l2_vp9_fw_update_probs(&vp9_ctx->probability_tables, prob_updates, dec_params); - - return 0; -} - -static int rkvdec_vp9_run(struct rkvdec_ctx *ctx) -{ - struct rkvdec_dev *rkvdec = ctx->dev; - struct rkvdec_vp9_run run = { }; - int ret; - - ret = rkvdec_vp9_run_preamble(ctx, &run); - if (ret) { - rkvdec_run_postamble(ctx, &run.base); - return ret; - } - - /* Prepare probs. */ - init_probs(ctx, &run); - - /* Configure hardware registers. */ - config_registers(ctx, &run); - - rkvdec_run_postamble(ctx, &run.base); - - schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000)); - - writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); - writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); - - writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN); - /* Start decoding! */ - writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E | - RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E, - rkvdec->regs + RKVDEC_REG_INTERRUPT); - - return 0; -} - -#define copy_tx_and_skip(p1, p2) \ -do { \ - memcpy((p1)->tx8, (p2)->tx8, sizeof((p1)->tx8)); \ - memcpy((p1)->tx16, (p2)->tx16, sizeof((p1)->tx16)); \ - memcpy((p1)->tx32, (p2)->tx32, sizeof((p1)->tx32)); \ - memcpy((p1)->skip, (p2)->skip, sizeof((p1)->skip)); \ -} while (0) - -static void rkvdec_vp9_done(struct rkvdec_ctx *ctx, - struct vb2_v4l2_buffer *src_buf, - struct vb2_v4l2_buffer *dst_buf, - enum vb2_buffer_state result) -{ - struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; - unsigned int fctx_idx; - - /* v4l2-specific stuff */ - if (result == VB2_BUF_STATE_ERROR) - goto out_update_last; - - /* - * vp9 stuff - * - * 6.1.2 refresh_probs() - * - * In the spec a complementary condition goes last in 6.1.2 refresh_probs(), - * but it makes no sense to perform all the activities from the first "if" - * there if we actually are not refreshing the frame context. On top of that, - * because of 6.2 uncompressed_header() whenever error_resilient_mode == 1, - * refresh_frame_context == 0. Consequently, if we don't jump to out_update_last - * it means error_resilient_mode must be 0. - */ - if (!(vp9_ctx->cur.flags & V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX)) - goto out_update_last; - - fctx_idx = vp9_ctx->cur.frame_context_idx; - - if (!(vp9_ctx->cur.flags & V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE)) { - /* error_resilient_mode == 0 && frame_parallel_decoding_mode == 0 */ - struct v4l2_vp9_frame_context *probs = &vp9_ctx->probability_tables; - bool frame_is_intra = vp9_ctx->cur.flags & - (V4L2_VP9_FRAME_FLAG_KEY_FRAME | V4L2_VP9_FRAME_FLAG_INTRA_ONLY); - struct tx_and_skip { - u8 tx8[2][1]; - u8 tx16[2][2]; - u8 tx32[2][3]; - u8 skip[3]; - } _tx_skip, *tx_skip = &_tx_skip; - struct v4l2_vp9_frame_symbol_counts *counts; - - /* buffer the forward-updated TX and skip probs */ - if (frame_is_intra) - copy_tx_and_skip(tx_skip, probs); - - /* 6.1.2 refresh_probs(): load_probs() and load_probs2() */ - *probs = vp9_ctx->frame_context[fctx_idx]; - - /* if FrameIsIntra then undo the effect of load_probs2() */ - if (frame_is_intra) - copy_tx_and_skip(probs, tx_skip); - - counts = frame_is_intra ? &vp9_ctx->intra_cnts : &vp9_ctx->inter_cnts; - v4l2_vp9_adapt_coef_probs(probs, counts, - !vp9_ctx->last.valid || - vp9_ctx->last.flags & V4L2_VP9_FRAME_FLAG_KEY_FRAME, - frame_is_intra); - if (!frame_is_intra) { - const struct rkvdec_vp9_inter_frame_symbol_counts *inter_cnts; - u32 classes[2][11]; - int i; - - inter_cnts = vp9_ctx->count_tbl.cpu; - for (i = 0; i < ARRAY_SIZE(classes); ++i) - memcpy(classes[i], inter_cnts->classes[i], sizeof(classes[0])); - counts->classes = &classes; - - /* load_probs2() already done */ - v4l2_vp9_adapt_noncoef_probs(&vp9_ctx->probability_tables, counts, - vp9_ctx->cur.reference_mode, - vp9_ctx->cur.interpolation_filter, - vp9_ctx->cur.tx_mode, vp9_ctx->cur.flags); - } - } - - /* 6.1.2 refresh_probs(): save_probs(fctx_idx) */ - vp9_ctx->frame_context[fctx_idx] = vp9_ctx->probability_tables; - -out_update_last: - update_ctx_last_info(vp9_ctx); -} - -static void rkvdec_init_v4l2_vp9_count_tbl(struct rkvdec_ctx *ctx) -{ - struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; - struct rkvdec_vp9_intra_frame_symbol_counts *intra_cnts = vp9_ctx->count_tbl.cpu; - struct rkvdec_vp9_inter_frame_symbol_counts *inter_cnts = vp9_ctx->count_tbl.cpu; - int i, j, k, l, m; - - vp9_ctx->inter_cnts.partition = &inter_cnts->partition; - vp9_ctx->inter_cnts.skip = &inter_cnts->skip; - vp9_ctx->inter_cnts.intra_inter = &inter_cnts->inter; - vp9_ctx->inter_cnts.tx32p = &inter_cnts->tx32p; - vp9_ctx->inter_cnts.tx16p = &inter_cnts->tx16p; - vp9_ctx->inter_cnts.tx8p = &inter_cnts->tx8p; - - vp9_ctx->intra_cnts.partition = (u32 (*)[16][4])(&intra_cnts->partition); - vp9_ctx->intra_cnts.skip = &intra_cnts->skip; - vp9_ctx->intra_cnts.intra_inter = &intra_cnts->intra; - vp9_ctx->intra_cnts.tx32p = &intra_cnts->tx32p; - vp9_ctx->intra_cnts.tx16p = &intra_cnts->tx16p; - vp9_ctx->intra_cnts.tx8p = &intra_cnts->tx8p; - - vp9_ctx->inter_cnts.y_mode = &inter_cnts->y_mode; - vp9_ctx->inter_cnts.uv_mode = &inter_cnts->uv_mode; - vp9_ctx->inter_cnts.comp = &inter_cnts->comp; - vp9_ctx->inter_cnts.comp_ref = &inter_cnts->comp_ref; - vp9_ctx->inter_cnts.single_ref = &inter_cnts->single_ref; - vp9_ctx->inter_cnts.mv_mode = &inter_cnts->mv_mode; - vp9_ctx->inter_cnts.filter = &inter_cnts->filter; - vp9_ctx->inter_cnts.mv_joint = &inter_cnts->mv_joint; - vp9_ctx->inter_cnts.sign = &inter_cnts->sign; - /* - * rk hardware actually uses "u32 classes[2][11 + 1];" - * instead of "u32 classes[2][11];", so this must be explicitly - * copied into vp9_ctx->classes when passing the data to the - * vp9 library function - */ - vp9_ctx->inter_cnts.class0 = &inter_cnts->class0; - vp9_ctx->inter_cnts.bits = &inter_cnts->bits; - vp9_ctx->inter_cnts.class0_fp = &inter_cnts->class0_fp; - vp9_ctx->inter_cnts.fp = &inter_cnts->fp; - vp9_ctx->inter_cnts.class0_hp = &inter_cnts->class0_hp; - vp9_ctx->inter_cnts.hp = &inter_cnts->hp; - -#define INNERMOST_LOOP \ - do { \ - for (m = 0; m < ARRAY_SIZE(vp9_ctx->inter_cnts.coeff[0][0][0][0]); ++m) {\ - vp9_ctx->inter_cnts.coeff[i][j][k][l][m] = \ - &inter_cnts->ref_cnt[k][i][j][l][m].coeff; \ - vp9_ctx->inter_cnts.eob[i][j][k][l][m][0] = \ - &inter_cnts->ref_cnt[k][i][j][l][m].eob[0]; \ - vp9_ctx->inter_cnts.eob[i][j][k][l][m][1] = \ - &inter_cnts->ref_cnt[k][i][j][l][m].eob[1]; \ - \ - vp9_ctx->intra_cnts.coeff[i][j][k][l][m] = \ - &intra_cnts->ref_cnt[k][i][j][l][m].coeff; \ - vp9_ctx->intra_cnts.eob[i][j][k][l][m][0] = \ - &intra_cnts->ref_cnt[k][i][j][l][m].eob[0]; \ - vp9_ctx->intra_cnts.eob[i][j][k][l][m][1] = \ - &intra_cnts->ref_cnt[k][i][j][l][m].eob[1]; \ - } \ - } while (0) - - for (i = 0; i < ARRAY_SIZE(vp9_ctx->inter_cnts.coeff); ++i) - for (j = 0; j < ARRAY_SIZE(vp9_ctx->inter_cnts.coeff[0]); ++j) - for (k = 0; k < ARRAY_SIZE(vp9_ctx->inter_cnts.coeff[0][0]); ++k) - for (l = 0; l < ARRAY_SIZE(vp9_ctx->inter_cnts.coeff[0][0][0]); ++l) - INNERMOST_LOOP; -#undef INNERMOST_LOOP -} - -static int rkvdec_vp9_start(struct rkvdec_ctx *ctx) -{ - struct rkvdec_dev *rkvdec = ctx->dev; - struct rkvdec_vp9_priv_tbl *priv_tbl; - struct rkvdec_vp9_ctx *vp9_ctx; - unsigned char *count_tbl; - int ret; - - vp9_ctx = kzalloc(sizeof(*vp9_ctx), GFP_KERNEL); - if (!vp9_ctx) - return -ENOMEM; - - ctx->priv = vp9_ctx; - - BUILD_BUG_ON(sizeof(priv_tbl->probs) % 16); /* ensure probs size is 128-bit aligned */ - priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), - &vp9_ctx->priv_tbl.dma, GFP_KERNEL); - if (!priv_tbl) { - ret = -ENOMEM; - goto err_free_ctx; - } - - vp9_ctx->priv_tbl.size = sizeof(*priv_tbl); - vp9_ctx->priv_tbl.cpu = priv_tbl; - - count_tbl = dma_alloc_coherent(rkvdec->dev, RKVDEC_VP9_COUNT_SIZE, - &vp9_ctx->count_tbl.dma, GFP_KERNEL); - if (!count_tbl) { - ret = -ENOMEM; - goto err_free_priv_tbl; - } - - vp9_ctx->count_tbl.size = RKVDEC_VP9_COUNT_SIZE; - vp9_ctx->count_tbl.cpu = count_tbl; - rkvdec_init_v4l2_vp9_count_tbl(ctx); - - return 0; - -err_free_priv_tbl: - dma_free_coherent(rkvdec->dev, vp9_ctx->priv_tbl.size, - vp9_ctx->priv_tbl.cpu, vp9_ctx->priv_tbl.dma); - -err_free_ctx: - kfree(vp9_ctx); - return ret; -} - -static void rkvdec_vp9_stop(struct rkvdec_ctx *ctx) -{ - struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; - struct rkvdec_dev *rkvdec = ctx->dev; - - dma_free_coherent(rkvdec->dev, vp9_ctx->count_tbl.size, - vp9_ctx->count_tbl.cpu, vp9_ctx->count_tbl.dma); - dma_free_coherent(rkvdec->dev, vp9_ctx->priv_tbl.size, - vp9_ctx->priv_tbl.cpu, vp9_ctx->priv_tbl.dma); - kfree(vp9_ctx); -} - -static int rkvdec_vp9_adjust_fmt(struct rkvdec_ctx *ctx, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp; - - fmt->num_planes = 1; - if (!fmt->plane_fmt[0].sizeimage) - fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * 2; - return 0; -} - -const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops = { - .adjust_fmt = rkvdec_vp9_adjust_fmt, - .start = rkvdec_vp9_start, - .stop = rkvdec_vp9_stop, - .run = rkvdec_vp9_run, - .done = rkvdec_vp9_done, -}; diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c deleted file mode 100644 index 3367902f22de3..0000000000000 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ /dev/null @@ -1,1222 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip Video Decoder driver - * - * Copyright (C) 2019 Collabora, Ltd. - * - * Based on rkvdec driver by Google LLC. (Tomasz Figa <tfiga@chromium.org>) - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - */ - -#include <linux/clk.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/pm.h> -#include <linux/pm_runtime.h> -#include <linux/slab.h> -#include <linux/videodev2.h> -#include <linux/workqueue.h> -#include <media/v4l2-event.h> -#include <media/v4l2-mem2mem.h> -#include <media/videobuf2-core.h> -#include <media/videobuf2-vmalloc.h> - -#include "rkvdec.h" -#include "rkvdec-regs.h" - -static bool rkvdec_image_fmt_match(enum rkvdec_image_fmt fmt1, - enum rkvdec_image_fmt fmt2) -{ - return fmt1 == fmt2 || fmt2 == RKVDEC_IMG_FMT_ANY || - fmt1 == RKVDEC_IMG_FMT_ANY; -} - -static bool rkvdec_image_fmt_changed(struct rkvdec_ctx *ctx, - enum rkvdec_image_fmt image_fmt) -{ - if (image_fmt == RKVDEC_IMG_FMT_ANY) - return false; - - return ctx->image_fmt != image_fmt; -} - -static u32 rkvdec_enum_decoded_fmt(struct rkvdec_ctx *ctx, int index, - enum rkvdec_image_fmt image_fmt) -{ - const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc; - int fmt_idx = -1; - unsigned int i; - - if (WARN_ON(!desc)) - return 0; - - for (i = 0; i < desc->num_decoded_fmts; i++) { - if (!rkvdec_image_fmt_match(desc->decoded_fmts[i].image_fmt, - image_fmt)) - continue; - fmt_idx++; - if (index == fmt_idx) - return desc->decoded_fmts[i].fourcc; - } - - return 0; -} - -static bool rkvdec_is_valid_fmt(struct rkvdec_ctx *ctx, u32 fourcc, - enum rkvdec_image_fmt image_fmt) -{ - const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc; - unsigned int i; - - for (i = 0; i < desc->num_decoded_fmts; i++) { - if (rkvdec_image_fmt_match(desc->decoded_fmts[i].image_fmt, - image_fmt) && - desc->decoded_fmts[i].fourcc == fourcc) - return true; - } - - return false; -} - -static void rkvdec_fill_decoded_pixfmt(struct rkvdec_ctx *ctx, - struct v4l2_pix_format_mplane *pix_mp) -{ - v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, - pix_mp->width, pix_mp->height); - pix_mp->plane_fmt[0].sizeimage += 128 * - DIV_ROUND_UP(pix_mp->width, 16) * - DIV_ROUND_UP(pix_mp->height, 16); -} - -static void rkvdec_reset_fmt(struct rkvdec_ctx *ctx, struct v4l2_format *f, - u32 fourcc) -{ - memset(f, 0, sizeof(*f)); - f->fmt.pix_mp.pixelformat = fourcc; - f->fmt.pix_mp.field = V4L2_FIELD_NONE; - f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; - f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; - f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; -} - -static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx) -{ - struct v4l2_format *f = &ctx->decoded_fmt; - u32 fourcc; - - fourcc = rkvdec_enum_decoded_fmt(ctx, 0, ctx->image_fmt); - rkvdec_reset_fmt(ctx, f, fourcc); - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - f->fmt.pix_mp.width = ctx->coded_fmt.fmt.pix_mp.width; - f->fmt.pix_mp.height = ctx->coded_fmt.fmt.pix_mp.height; - rkvdec_fill_decoded_pixfmt(ctx, &f->fmt.pix_mp); -} - -static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) -{ - struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); - const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc; - - if (desc->ops->try_ctrl) - return desc->ops->try_ctrl(ctx, ctrl); - - return 0; -} - -static int rkvdec_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); - const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc; - enum rkvdec_image_fmt image_fmt; - struct vb2_queue *vq; - - /* Check if this change requires a capture format reset */ - if (!desc->ops->get_image_fmt) - return 0; - - image_fmt = desc->ops->get_image_fmt(ctx, ctrl); - if (rkvdec_image_fmt_changed(ctx, image_fmt)) { - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (vb2_is_busy(vq)) - return -EBUSY; - - ctx->image_fmt = image_fmt; - rkvdec_reset_decoded_fmt(ctx); - } - - return 0; -} - -static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = { - .try_ctrl = rkvdec_try_ctrl, - .s_ctrl = rkvdec_s_ctrl, -}; - -static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { - { - .cfg.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, - }, - { - .cfg.id = V4L2_CID_STATELESS_H264_SPS, - .cfg.ops = &rkvdec_ctrl_ops, - }, - { - .cfg.id = V4L2_CID_STATELESS_H264_PPS, - }, - { - .cfg.id = V4L2_CID_STATELESS_H264_SCALING_MATRIX, - }, - { - .cfg.id = V4L2_CID_STATELESS_H264_DECODE_MODE, - .cfg.min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, - .cfg.max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, - .cfg.def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, - }, - { - .cfg.id = V4L2_CID_STATELESS_H264_START_CODE, - .cfg.min = V4L2_STATELESS_H264_START_CODE_ANNEX_B, - .cfg.def = V4L2_STATELESS_H264_START_CODE_ANNEX_B, - .cfg.max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, - }, - { - .cfg.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, - .cfg.min = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE, - .cfg.max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA, - .cfg.menu_skip_mask = - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE), - .cfg.def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, - }, - { - .cfg.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, - .cfg.min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, - .cfg.max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, - }, -}; - -static const struct rkvdec_ctrls rkvdec_h264_ctrls = { - .ctrls = rkvdec_h264_ctrl_descs, - .num_ctrls = ARRAY_SIZE(rkvdec_h264_ctrl_descs), -}; - -static const struct rkvdec_decoded_fmt_desc rkvdec_h264_decoded_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_NV12, - .image_fmt = RKVDEC_IMG_FMT_420_8BIT, - }, - { - .fourcc = V4L2_PIX_FMT_NV15, - .image_fmt = RKVDEC_IMG_FMT_420_10BIT, - }, - { - .fourcc = V4L2_PIX_FMT_NV16, - .image_fmt = RKVDEC_IMG_FMT_422_8BIT, - }, - { - .fourcc = V4L2_PIX_FMT_NV20, - .image_fmt = RKVDEC_IMG_FMT_422_10BIT, - }, -}; - -static const struct rkvdec_ctrl_desc rkvdec_vp9_ctrl_descs[] = { - { - .cfg.id = V4L2_CID_STATELESS_VP9_FRAME, - }, - { - .cfg.id = V4L2_CID_STATELESS_VP9_COMPRESSED_HDR, - }, - { - .cfg.id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE, - .cfg.min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, - .cfg.max = V4L2_MPEG_VIDEO_VP9_PROFILE_0, - .cfg.def = V4L2_MPEG_VIDEO_VP9_PROFILE_0, - }, -}; - -static const struct rkvdec_ctrls rkvdec_vp9_ctrls = { - .ctrls = rkvdec_vp9_ctrl_descs, - .num_ctrls = ARRAY_SIZE(rkvdec_vp9_ctrl_descs), -}; - -static const struct rkvdec_decoded_fmt_desc rkvdec_vp9_decoded_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_NV12, - .image_fmt = RKVDEC_IMG_FMT_420_8BIT, - }, -}; - -static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_H264_SLICE, - .frmsize = { - .min_width = 64, - .max_width = 4096, - .step_width = 64, - .min_height = 48, - .max_height = 2560, - .step_height = 16, - }, - .ctrls = &rkvdec_h264_ctrls, - .ops = &rkvdec_h264_fmt_ops, - .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts), - .decoded_fmts = rkvdec_h264_decoded_fmts, - .subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF, - }, - { - .fourcc = V4L2_PIX_FMT_VP9_FRAME, - .frmsize = { - .min_width = 64, - .max_width = 4096, - .step_width = 64, - .min_height = 64, - .max_height = 2304, - .step_height = 64, - }, - .ctrls = &rkvdec_vp9_ctrls, - .ops = &rkvdec_vp9_fmt_ops, - .num_decoded_fmts = ARRAY_SIZE(rkvdec_vp9_decoded_fmts), - .decoded_fmts = rkvdec_vp9_decoded_fmts, - } -}; - -static const struct rkvdec_coded_fmt_desc * -rkvdec_find_coded_fmt_desc(u32 fourcc) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) { - if (rkvdec_coded_fmts[i].fourcc == fourcc) - return &rkvdec_coded_fmts[i]; - } - - return NULL; -} - -static void rkvdec_reset_coded_fmt(struct rkvdec_ctx *ctx) -{ - struct v4l2_format *f = &ctx->coded_fmt; - - ctx->coded_fmt_desc = &rkvdec_coded_fmts[0]; - rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->fourcc); - - f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - f->fmt.pix_mp.width = ctx->coded_fmt_desc->frmsize.min_width; - f->fmt.pix_mp.height = ctx->coded_fmt_desc->frmsize.min_height; - - if (ctx->coded_fmt_desc->ops->adjust_fmt) - ctx->coded_fmt_desc->ops->adjust_fmt(ctx, f); -} - -static int rkvdec_enum_framesizes(struct file *file, void *priv, - struct v4l2_frmsizeenum *fsize) -{ - const struct rkvdec_coded_fmt_desc *fmt; - - if (fsize->index != 0) - return -EINVAL; - - fmt = rkvdec_find_coded_fmt_desc(fsize->pixel_format); - if (!fmt) - return -EINVAL; - - fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; - fsize->stepwise.min_width = 1; - fsize->stepwise.max_width = fmt->frmsize.max_width; - fsize->stepwise.step_width = 1; - fsize->stepwise.min_height = 1; - fsize->stepwise.max_height = fmt->frmsize.max_height; - fsize->stepwise.step_height = 1; - - return 0; -} - -static int rkvdec_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct rkvdec_dev *rkvdec = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - - strscpy(cap->driver, rkvdec->dev->driver->name, - sizeof(cap->driver)); - strscpy(cap->card, vdev->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - rkvdec->dev->driver->name); - return 0; -} - -static int rkvdec_try_capture_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); - const struct rkvdec_coded_fmt_desc *coded_desc; - - /* - * The codec context should point to a coded format desc, if the format - * on the coded end has not been set yet, it should point to the - * default value. - */ - coded_desc = ctx->coded_fmt_desc; - if (WARN_ON(!coded_desc)) - return -EINVAL; - - if (!rkvdec_is_valid_fmt(ctx, pix_mp->pixelformat, ctx->image_fmt)) - pix_mp->pixelformat = rkvdec_enum_decoded_fmt(ctx, 0, - ctx->image_fmt); - - /* Always apply the frmsize constraint of the coded end. */ - pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width); - pix_mp->height = max(pix_mp->height, ctx->coded_fmt.fmt.pix_mp.height); - v4l2_apply_frmsize_constraints(&pix_mp->width, - &pix_mp->height, - &coded_desc->frmsize); - - rkvdec_fill_decoded_pixfmt(ctx, pix_mp); - pix_mp->field = V4L2_FIELD_NONE; - - return 0; -} - -static int rkvdec_try_output_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); - const struct rkvdec_coded_fmt_desc *desc; - - desc = rkvdec_find_coded_fmt_desc(pix_mp->pixelformat); - if (!desc) { - pix_mp->pixelformat = rkvdec_coded_fmts[0].fourcc; - desc = &rkvdec_coded_fmts[0]; - } - - v4l2_apply_frmsize_constraints(&pix_mp->width, - &pix_mp->height, - &desc->frmsize); - - pix_mp->field = V4L2_FIELD_NONE; - /* All coded formats are considered single planar for now. */ - pix_mp->num_planes = 1; - - if (desc->ops->adjust_fmt) { - int ret; - - ret = desc->ops->adjust_fmt(ctx, f); - if (ret) - return ret; - } - - return 0; -} - -static int rkvdec_s_capture_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); - struct vb2_queue *vq; - int ret; - - /* Change not allowed if queue is busy */ - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (vb2_is_busy(vq)) - return -EBUSY; - - ret = rkvdec_try_capture_fmt(file, priv, f); - if (ret) - return ret; - - ctx->decoded_fmt = *f; - return 0; -} - -static int rkvdec_s_output_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); - struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; - const struct rkvdec_coded_fmt_desc *desc; - struct v4l2_format *cap_fmt; - struct vb2_queue *peer_vq, *vq; - int ret; - - /* - * In order to support dynamic resolution change, the decoder admits - * a resolution change, as long as the pixelformat remains. Can't be - * done if streaming. - */ - vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (vb2_is_streaming(vq) || - (vb2_is_busy(vq) && - f->fmt.pix_mp.pixelformat != ctx->coded_fmt.fmt.pix_mp.pixelformat)) - return -EBUSY; - - /* - * Since format change on the OUTPUT queue will reset the CAPTURE - * queue, we can't allow doing so when the CAPTURE queue has buffers - * allocated. - */ - peer_vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (vb2_is_busy(peer_vq)) - return -EBUSY; - - ret = rkvdec_try_output_fmt(file, priv, f); - if (ret) - return ret; - - desc = rkvdec_find_coded_fmt_desc(f->fmt.pix_mp.pixelformat); - if (!desc) - return -EINVAL; - ctx->coded_fmt_desc = desc; - ctx->coded_fmt = *f; - - /* - * Current decoded format might have become invalid with newly - * selected codec, so reset it to default just to be safe and - * keep internal driver state sane. User is mandated to set - * the decoded format again after we return, so we don't need - * anything smarter. - * - * Note that this will propagates any size changes to the decoded format. - */ - ctx->image_fmt = RKVDEC_IMG_FMT_ANY; - rkvdec_reset_decoded_fmt(ctx); - - /* Propagate colorspace information to capture. */ - cap_fmt = &ctx->decoded_fmt; - cap_fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; - cap_fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; - cap_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; - cap_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; - - /* Enable format specific queue features */ - vq->subsystem_flags |= desc->subsystem_flags; - - return 0; -} - -static int rkvdec_g_output_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); - - *f = ctx->coded_fmt; - return 0; -} - -static int rkvdec_g_capture_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); - - *f = ctx->decoded_fmt; - return 0; -} - -static int rkvdec_enum_output_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index >= ARRAY_SIZE(rkvdec_coded_fmts)) - return -EINVAL; - - f->pixelformat = rkvdec_coded_fmts[f->index].fourcc; - return 0; -} - -static int rkvdec_enum_capture_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); - u32 fourcc; - - fourcc = rkvdec_enum_decoded_fmt(ctx, f->index, ctx->image_fmt); - if (!fourcc) - return -EINVAL; - - f->pixelformat = fourcc; - return 0; -} - -static const struct v4l2_ioctl_ops rkvdec_ioctl_ops = { - .vidioc_querycap = rkvdec_querycap, - .vidioc_enum_framesizes = rkvdec_enum_framesizes, - - .vidioc_try_fmt_vid_cap_mplane = rkvdec_try_capture_fmt, - .vidioc_try_fmt_vid_out_mplane = rkvdec_try_output_fmt, - .vidioc_s_fmt_vid_out_mplane = rkvdec_s_output_fmt, - .vidioc_s_fmt_vid_cap_mplane = rkvdec_s_capture_fmt, - .vidioc_g_fmt_vid_out_mplane = rkvdec_g_output_fmt, - .vidioc_g_fmt_vid_cap_mplane = rkvdec_g_capture_fmt, - .vidioc_enum_fmt_vid_out = rkvdec_enum_output_fmt, - .vidioc_enum_fmt_vid_cap = rkvdec_enum_capture_fmt, - - .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, - .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, - .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, - .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, - .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, - .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, - .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - - .vidioc_streamon = v4l2_m2m_ioctl_streamon, - .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, - - .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd, - .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd, -}; - -static int rkvdec_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, - unsigned int *num_planes, unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct rkvdec_ctx *ctx = vb2_get_drv_priv(vq); - struct v4l2_format *f; - unsigned int i; - - if (V4L2_TYPE_IS_OUTPUT(vq->type)) - f = &ctx->coded_fmt; - else - f = &ctx->decoded_fmt; - - if (*num_planes) { - if (*num_planes != f->fmt.pix_mp.num_planes) - return -EINVAL; - - for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { - if (sizes[i] < f->fmt.pix_mp.plane_fmt[i].sizeimage) - return -EINVAL; - } - } else { - *num_planes = f->fmt.pix_mp.num_planes; - for (i = 0; i < f->fmt.pix_mp.num_planes; i++) - sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage; - } - - return 0; -} - -static int rkvdec_buf_prepare(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct rkvdec_ctx *ctx = vb2_get_drv_priv(vq); - struct v4l2_format *f; - unsigned int i; - - if (V4L2_TYPE_IS_OUTPUT(vq->type)) - f = &ctx->coded_fmt; - else - f = &ctx->decoded_fmt; - - for (i = 0; i < f->fmt.pix_mp.num_planes; ++i) { - u32 sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; - - if (vb2_plane_size(vb, i) < sizeimage) - return -EINVAL; - } - - /* - * Buffer's bytesused must be written by driver for CAPTURE buffers. - * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets - * it to buffer length). - */ - if (V4L2_TYPE_IS_CAPTURE(vq->type)) - vb2_set_plane_payload(vb, 0, f->fmt.pix_mp.plane_fmt[0].sizeimage); - - return 0; -} - -static void rkvdec_buf_queue(struct vb2_buffer *vb) -{ - struct rkvdec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); -} - -static int rkvdec_buf_out_validate(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - - vbuf->field = V4L2_FIELD_NONE; - return 0; -} - -static void rkvdec_buf_request_complete(struct vb2_buffer *vb) -{ - struct rkvdec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->ctrl_hdl); -} - -static int rkvdec_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct rkvdec_ctx *ctx = vb2_get_drv_priv(q); - const struct rkvdec_coded_fmt_desc *desc; - int ret; - - if (V4L2_TYPE_IS_CAPTURE(q->type)) - return 0; - - desc = ctx->coded_fmt_desc; - if (WARN_ON(!desc)) - return -EINVAL; - - if (desc->ops->start) { - ret = desc->ops->start(ctx); - if (ret) - return ret; - } - - return 0; -} - -static void rkvdec_queue_cleanup(struct vb2_queue *vq, u32 state) -{ - struct rkvdec_ctx *ctx = vb2_get_drv_priv(vq); - - while (true) { - struct vb2_v4l2_buffer *vbuf; - - if (V4L2_TYPE_IS_OUTPUT(vq->type)) - vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - else - vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - - if (!vbuf) - break; - - v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, - &ctx->ctrl_hdl); - v4l2_m2m_buf_done(vbuf, state); - } -} - -static void rkvdec_stop_streaming(struct vb2_queue *q) -{ - struct rkvdec_ctx *ctx = vb2_get_drv_priv(q); - - if (V4L2_TYPE_IS_OUTPUT(q->type)) { - const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc; - - if (WARN_ON(!desc)) - return; - - if (desc->ops->stop) - desc->ops->stop(ctx); - } - - rkvdec_queue_cleanup(q, VB2_BUF_STATE_ERROR); -} - -static const struct vb2_ops rkvdec_queue_ops = { - .queue_setup = rkvdec_queue_setup, - .buf_prepare = rkvdec_buf_prepare, - .buf_queue = rkvdec_buf_queue, - .buf_out_validate = rkvdec_buf_out_validate, - .buf_request_complete = rkvdec_buf_request_complete, - .start_streaming = rkvdec_start_streaming, - .stop_streaming = rkvdec_stop_streaming, -}; - -static int rkvdec_request_validate(struct media_request *req) -{ - unsigned int count; - - count = vb2_request_buffer_cnt(req); - if (!count) - return -ENOENT; - else if (count > 1) - return -EINVAL; - - return vb2_request_validate(req); -} - -static const struct media_device_ops rkvdec_media_ops = { - .req_validate = rkvdec_request_validate, - .req_queue = v4l2_m2m_request_queue, -}; - -static void rkvdec_job_finish_no_pm(struct rkvdec_ctx *ctx, - enum vb2_buffer_state result) -{ - if (ctx->coded_fmt_desc->ops->done) { - struct vb2_v4l2_buffer *src_buf, *dst_buf; - - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - ctx->coded_fmt_desc->ops->done(ctx, src_buf, dst_buf, result); - } - - v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx, - result); -} - -static void rkvdec_job_finish(struct rkvdec_ctx *ctx, - enum vb2_buffer_state result) -{ - struct rkvdec_dev *rkvdec = ctx->dev; - - pm_runtime_mark_last_busy(rkvdec->dev); - pm_runtime_put_autosuspend(rkvdec->dev); - rkvdec_job_finish_no_pm(ctx, result); -} - -void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run) -{ - struct media_request *src_req; - - memset(run, 0, sizeof(*run)); - - run->bufs.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - run->bufs.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - - /* Apply request(s) controls if needed. */ - src_req = run->bufs.src->vb2_buf.req_obj.req; - if (src_req) - v4l2_ctrl_request_setup(src_req, &ctx->ctrl_hdl); - - v4l2_m2m_buf_copy_metadata(run->bufs.src, run->bufs.dst, true); -} - -void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run) -{ - struct media_request *src_req = run->bufs.src->vb2_buf.req_obj.req; - - if (src_req) - v4l2_ctrl_request_complete(src_req, &ctx->ctrl_hdl); -} - -static void rkvdec_device_run(void *priv) -{ - struct rkvdec_ctx *ctx = priv; - struct rkvdec_dev *rkvdec = ctx->dev; - const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc; - int ret; - - if (WARN_ON(!desc)) - return; - - ret = pm_runtime_resume_and_get(rkvdec->dev); - if (ret < 0) { - rkvdec_job_finish_no_pm(ctx, VB2_BUF_STATE_ERROR); - return; - } - - ret = desc->ops->run(ctx); - if (ret) - rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR); -} - -static const struct v4l2_m2m_ops rkvdec_m2m_ops = { - .device_run = rkvdec_device_run, -}; - -static int rkvdec_queue_init(void *priv, - struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) -{ - struct rkvdec_ctx *ctx = priv; - struct rkvdec_dev *rkvdec = ctx->dev; - int ret; - - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - src_vq->io_modes = VB2_MMAP | VB2_DMABUF; - src_vq->drv_priv = ctx; - src_vq->ops = &rkvdec_queue_ops; - src_vq->mem_ops = &vb2_dma_contig_memops; - - /* - * Driver does mostly sequential access, so sacrifice TLB efficiency - * for faster allocation. Also, no CPU access on the source queue, - * so no kernel mapping needed. - */ - src_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | - DMA_ATTR_NO_KERNEL_MAPPING; - src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->lock = &rkvdec->vdev_lock; - src_vq->dev = rkvdec->v4l2_dev.dev; - src_vq->supports_requests = true; - src_vq->requires_requests = true; - - ret = vb2_queue_init(src_vq); - if (ret) - return ret; - - dst_vq->bidirectional = true; - dst_vq->mem_ops = &vb2_dma_contig_memops; - dst_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | - DMA_ATTR_NO_KERNEL_MAPPING; - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; - dst_vq->drv_priv = ctx; - dst_vq->ops = &rkvdec_queue_ops; - dst_vq->buf_struct_size = sizeof(struct rkvdec_decoded_buffer); - dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - dst_vq->lock = &rkvdec->vdev_lock; - dst_vq->dev = rkvdec->v4l2_dev.dev; - - return vb2_queue_init(dst_vq); -} - -static int rkvdec_add_ctrls(struct rkvdec_ctx *ctx, - const struct rkvdec_ctrls *ctrls) -{ - unsigned int i; - - for (i = 0; i < ctrls->num_ctrls; i++) { - const struct v4l2_ctrl_config *cfg = &ctrls->ctrls[i].cfg; - - v4l2_ctrl_new_custom(&ctx->ctrl_hdl, cfg, ctx); - if (ctx->ctrl_hdl.error) - return ctx->ctrl_hdl.error; - } - - return 0; -} - -static int rkvdec_init_ctrls(struct rkvdec_ctx *ctx) -{ - unsigned int i, nctrls = 0; - int ret; - - for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) - nctrls += rkvdec_coded_fmts[i].ctrls->num_ctrls; - - v4l2_ctrl_handler_init(&ctx->ctrl_hdl, nctrls); - - for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) { - ret = rkvdec_add_ctrls(ctx, rkvdec_coded_fmts[i].ctrls); - if (ret) - goto err_free_handler; - } - - ret = v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); - if (ret) - goto err_free_handler; - - ctx->fh.ctrl_handler = &ctx->ctrl_hdl; - return 0; - -err_free_handler: - v4l2_ctrl_handler_free(&ctx->ctrl_hdl); - return ret; -} - -static int rkvdec_open(struct file *filp) -{ - struct rkvdec_dev *rkvdec = video_drvdata(filp); - struct rkvdec_ctx *ctx; - int ret; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->dev = rkvdec; - rkvdec_reset_coded_fmt(ctx); - rkvdec_reset_decoded_fmt(ctx); - v4l2_fh_init(&ctx->fh, video_devdata(filp)); - - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rkvdec->m2m_dev, ctx, - rkvdec_queue_init); - if (IS_ERR(ctx->fh.m2m_ctx)) { - ret = PTR_ERR(ctx->fh.m2m_ctx); - goto err_free_ctx; - } - - ret = rkvdec_init_ctrls(ctx); - if (ret) - goto err_cleanup_m2m_ctx; - - filp->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); - - return 0; - -err_cleanup_m2m_ctx: - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - -err_free_ctx: - kfree(ctx); - return ret; -} - -static int rkvdec_release(struct file *filp) -{ - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(filp->private_data); - - v4l2_fh_del(&ctx->fh); - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_ctrl_handler_free(&ctx->ctrl_hdl); - v4l2_fh_exit(&ctx->fh); - kfree(ctx); - - return 0; -} - -static const struct v4l2_file_operations rkvdec_fops = { - .owner = THIS_MODULE, - .open = rkvdec_open, - .release = rkvdec_release, - .poll = v4l2_m2m_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = v4l2_m2m_fop_mmap, -}; - -static int rkvdec_v4l2_init(struct rkvdec_dev *rkvdec) -{ - int ret; - - ret = v4l2_device_register(rkvdec->dev, &rkvdec->v4l2_dev); - if (ret) { - dev_err(rkvdec->dev, "Failed to register V4L2 device\n"); - return ret; - } - - rkvdec->m2m_dev = v4l2_m2m_init(&rkvdec_m2m_ops); - if (IS_ERR(rkvdec->m2m_dev)) { - v4l2_err(&rkvdec->v4l2_dev, "Failed to init mem2mem device\n"); - ret = PTR_ERR(rkvdec->m2m_dev); - goto err_unregister_v4l2; - } - - rkvdec->mdev.dev = rkvdec->dev; - strscpy(rkvdec->mdev.model, "rkvdec", sizeof(rkvdec->mdev.model)); - strscpy(rkvdec->mdev.bus_info, "platform:rkvdec", - sizeof(rkvdec->mdev.bus_info)); - media_device_init(&rkvdec->mdev); - rkvdec->mdev.ops = &rkvdec_media_ops; - rkvdec->v4l2_dev.mdev = &rkvdec->mdev; - - rkvdec->vdev.lock = &rkvdec->vdev_lock; - rkvdec->vdev.v4l2_dev = &rkvdec->v4l2_dev; - rkvdec->vdev.fops = &rkvdec_fops; - rkvdec->vdev.release = video_device_release_empty; - rkvdec->vdev.vfl_dir = VFL_DIR_M2M; - rkvdec->vdev.device_caps = V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_M2M_MPLANE; - rkvdec->vdev.ioctl_ops = &rkvdec_ioctl_ops; - video_set_drvdata(&rkvdec->vdev, rkvdec); - strscpy(rkvdec->vdev.name, "rkvdec", sizeof(rkvdec->vdev.name)); - - ret = video_register_device(&rkvdec->vdev, VFL_TYPE_VIDEO, -1); - if (ret) { - v4l2_err(&rkvdec->v4l2_dev, "Failed to register video device\n"); - goto err_cleanup_mc; - } - - ret = v4l2_m2m_register_media_controller(rkvdec->m2m_dev, &rkvdec->vdev, - MEDIA_ENT_F_PROC_VIDEO_DECODER); - if (ret) { - v4l2_err(&rkvdec->v4l2_dev, - "Failed to initialize V4L2 M2M media controller\n"); - goto err_unregister_vdev; - } - - ret = media_device_register(&rkvdec->mdev); - if (ret) { - v4l2_err(&rkvdec->v4l2_dev, "Failed to register media device\n"); - goto err_unregister_mc; - } - - return 0; - -err_unregister_mc: - v4l2_m2m_unregister_media_controller(rkvdec->m2m_dev); - -err_unregister_vdev: - video_unregister_device(&rkvdec->vdev); - -err_cleanup_mc: - media_device_cleanup(&rkvdec->mdev); - v4l2_m2m_release(rkvdec->m2m_dev); - -err_unregister_v4l2: - v4l2_device_unregister(&rkvdec->v4l2_dev); - return ret; -} - -static void rkvdec_v4l2_cleanup(struct rkvdec_dev *rkvdec) -{ - media_device_unregister(&rkvdec->mdev); - v4l2_m2m_unregister_media_controller(rkvdec->m2m_dev); - video_unregister_device(&rkvdec->vdev); - media_device_cleanup(&rkvdec->mdev); - v4l2_m2m_release(rkvdec->m2m_dev); - v4l2_device_unregister(&rkvdec->v4l2_dev); -} - -static irqreturn_t rkvdec_irq_handler(int irq, void *priv) -{ - struct rkvdec_dev *rkvdec = priv; - enum vb2_buffer_state state; - u32 status; - - status = readl(rkvdec->regs + RKVDEC_REG_INTERRUPT); - state = (status & RKVDEC_RDY_STA) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - - writel(0, rkvdec->regs + RKVDEC_REG_INTERRUPT); - if (cancel_delayed_work(&rkvdec->watchdog_work)) { - struct rkvdec_ctx *ctx; - - ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); - rkvdec_job_finish(ctx, state); - } - - return IRQ_HANDLED; -} - -static void rkvdec_watchdog_func(struct work_struct *work) -{ - struct rkvdec_dev *rkvdec; - struct rkvdec_ctx *ctx; - - rkvdec = container_of(to_delayed_work(work), struct rkvdec_dev, - watchdog_work); - ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); - if (ctx) { - dev_err(rkvdec->dev, "Frame processing timed out!\n"); - writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT); - writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL); - rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR); - } -} - -static const struct of_device_id of_rkvdec_match[] = { - { .compatible = "rockchip,rk3399-vdec" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, of_rkvdec_match); - -static const char * const rkvdec_clk_names[] = { - "axi", "ahb", "cabac", "core" -}; - -static int rkvdec_probe(struct platform_device *pdev) -{ - struct rkvdec_dev *rkvdec; - unsigned int i; - int ret, irq; - - rkvdec = devm_kzalloc(&pdev->dev, sizeof(*rkvdec), GFP_KERNEL); - if (!rkvdec) - return -ENOMEM; - - platform_set_drvdata(pdev, rkvdec); - rkvdec->dev = &pdev->dev; - mutex_init(&rkvdec->vdev_lock); - INIT_DELAYED_WORK(&rkvdec->watchdog_work, rkvdec_watchdog_func); - - rkvdec->clocks = devm_kcalloc(&pdev->dev, ARRAY_SIZE(rkvdec_clk_names), - sizeof(*rkvdec->clocks), GFP_KERNEL); - if (!rkvdec->clocks) - return -ENOMEM; - - for (i = 0; i < ARRAY_SIZE(rkvdec_clk_names); i++) - rkvdec->clocks[i].id = rkvdec_clk_names[i]; - - ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(rkvdec_clk_names), - rkvdec->clocks); - if (ret) - return ret; - - rkvdec->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(rkvdec->regs)) - return PTR_ERR(rkvdec->regs); - - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(&pdev->dev, "Could not set DMA coherent mask.\n"); - return ret; - } - - vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return -ENXIO; - - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, - rkvdec_irq_handler, IRQF_ONESHOT, - dev_name(&pdev->dev), rkvdec); - if (ret) { - dev_err(&pdev->dev, "Could not request vdec IRQ\n"); - return ret; - } - - pm_runtime_set_autosuspend_delay(&pdev->dev, 100); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_enable(&pdev->dev); - - ret = rkvdec_v4l2_init(rkvdec); - if (ret) - goto err_disable_runtime_pm; - - return 0; - -err_disable_runtime_pm: - pm_runtime_dont_use_autosuspend(&pdev->dev); - pm_runtime_disable(&pdev->dev); - return ret; -} - -static void rkvdec_remove(struct platform_device *pdev) -{ - struct rkvdec_dev *rkvdec = platform_get_drvdata(pdev); - - cancel_delayed_work_sync(&rkvdec->watchdog_work); - - rkvdec_v4l2_cleanup(rkvdec); - pm_runtime_disable(&pdev->dev); - pm_runtime_dont_use_autosuspend(&pdev->dev); -} - -#ifdef CONFIG_PM -static int rkvdec_runtime_resume(struct device *dev) -{ - struct rkvdec_dev *rkvdec = dev_get_drvdata(dev); - - return clk_bulk_prepare_enable(ARRAY_SIZE(rkvdec_clk_names), - rkvdec->clocks); -} - -static int rkvdec_runtime_suspend(struct device *dev) -{ - struct rkvdec_dev *rkvdec = dev_get_drvdata(dev); - - clk_bulk_disable_unprepare(ARRAY_SIZE(rkvdec_clk_names), - rkvdec->clocks); - return 0; -} -#endif - -static const struct dev_pm_ops rkvdec_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(rkvdec_runtime_suspend, rkvdec_runtime_resume, NULL) -}; - -static struct platform_driver rkvdec_driver = { - .probe = rkvdec_probe, - .remove = rkvdec_remove, - .driver = { - .name = "rkvdec", - .of_match_table = of_rkvdec_match, - .pm = &rkvdec_pm_ops, - }, -}; -module_platform_driver(rkvdec_driver); - -MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>"); -MODULE_DESCRIPTION("Rockchip Video Decoder driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h deleted file mode 100644 index 9a9f4fced7a18..0000000000000 --- a/drivers/staging/media/rkvdec/rkvdec.h +++ /dev/null @@ -1,143 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Rockchip Video Decoder driver - * - * Copyright (C) 2019 Collabora, Ltd. - * - * Based on rkvdec driver by Google LLC. (Tomasz Figa <tfiga@chromium.org>) - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - */ -#ifndef RKVDEC_H_ -#define RKVDEC_H_ - -#include <linux/platform_device.h> -#include <linux/videodev2.h> -#include <linux/wait.h> -#include <linux/clk.h> - -#include <media/v4l2-ctrls.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ioctl.h> -#include <media/videobuf2-core.h> -#include <media/videobuf2-dma-contig.h> - -struct rkvdec_ctx; - -struct rkvdec_ctrl_desc { - struct v4l2_ctrl_config cfg; -}; - -struct rkvdec_ctrls { - const struct rkvdec_ctrl_desc *ctrls; - unsigned int num_ctrls; -}; - -struct rkvdec_run { - struct { - struct vb2_v4l2_buffer *src; - struct vb2_v4l2_buffer *dst; - } bufs; -}; - -struct rkvdec_vp9_decoded_buffer_info { - /* Info needed when the decoded frame serves as a reference frame. */ - unsigned short width; - unsigned short height; - unsigned int bit_depth : 4; -}; - -struct rkvdec_decoded_buffer { - /* Must be the first field in this struct. */ - struct v4l2_m2m_buffer base; - - union { - struct rkvdec_vp9_decoded_buffer_info vp9; - }; -}; - -static inline struct rkvdec_decoded_buffer * -vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf) -{ - return container_of(buf, struct rkvdec_decoded_buffer, - base.vb.vb2_buf); -} - -struct rkvdec_coded_fmt_ops { - int (*adjust_fmt)(struct rkvdec_ctx *ctx, - struct v4l2_format *f); - int (*start)(struct rkvdec_ctx *ctx); - void (*stop)(struct rkvdec_ctx *ctx); - int (*run)(struct rkvdec_ctx *ctx); - void (*done)(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *src_buf, - struct vb2_v4l2_buffer *dst_buf, - enum vb2_buffer_state result); - int (*try_ctrl)(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl); - enum rkvdec_image_fmt (*get_image_fmt)(struct rkvdec_ctx *ctx, - struct v4l2_ctrl *ctrl); -}; - -enum rkvdec_image_fmt { - RKVDEC_IMG_FMT_ANY = 0, - RKVDEC_IMG_FMT_420_8BIT, - RKVDEC_IMG_FMT_420_10BIT, - RKVDEC_IMG_FMT_422_8BIT, - RKVDEC_IMG_FMT_422_10BIT, -}; - -struct rkvdec_decoded_fmt_desc { - u32 fourcc; - enum rkvdec_image_fmt image_fmt; -}; - -struct rkvdec_coded_fmt_desc { - u32 fourcc; - struct v4l2_frmsize_stepwise frmsize; - const struct rkvdec_ctrls *ctrls; - const struct rkvdec_coded_fmt_ops *ops; - unsigned int num_decoded_fmts; - const struct rkvdec_decoded_fmt_desc *decoded_fmts; - u32 subsystem_flags; -}; - -struct rkvdec_dev { - struct v4l2_device v4l2_dev; - struct media_device mdev; - struct video_device vdev; - struct v4l2_m2m_dev *m2m_dev; - struct device *dev; - struct clk_bulk_data *clocks; - void __iomem *regs; - struct mutex vdev_lock; /* serializes ioctls */ - struct delayed_work watchdog_work; -}; - -struct rkvdec_ctx { - struct v4l2_fh fh; - struct v4l2_format coded_fmt; - struct v4l2_format decoded_fmt; - const struct rkvdec_coded_fmt_desc *coded_fmt_desc; - struct v4l2_ctrl_handler ctrl_hdl; - struct rkvdec_dev *dev; - enum rkvdec_image_fmt image_fmt; - void *priv; -}; - -static inline struct rkvdec_ctx *fh_to_rkvdec_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct rkvdec_ctx, fh); -} - -struct rkvdec_aux_buf { - void *cpu; - dma_addr_t dma; - size_t size; -}; - -void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); -void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); - -extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops; -extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops; - -#endif /* RKVDEC_H_ */ diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index 32af0e96e762b..444fb53878d12 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -86,9 +86,26 @@ void cedrus_dst_format_set(struct cedrus_dev *dev, switch (fmt->pixelformat) { case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: chroma_size = ALIGN(width, 16) * ALIGN(height, 16) / 2; - reg = VE_PRIMARY_OUT_FMT_NV12; + switch (fmt->pixelformat) { + case V4L2_PIX_FMT_NV12: + reg = VE_PRIMARY_OUT_FMT_NV12; + break; + case V4L2_PIX_FMT_NV21: + reg = VE_PRIMARY_OUT_FMT_NV21; + break; + case V4L2_PIX_FMT_YUV420: + reg = VE_PRIMARY_OUT_FMT_YU12; + break; + case V4L2_PIX_FMT_YVU420: + default: + reg = VE_PRIMARY_OUT_FMT_YV12; + break; + } cedrus_write(dev, VE_PRIMARY_OUT_FMT, reg); reg = chroma_size / 2; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 77f78266f4062..9fae2c7493d09 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -64,6 +64,21 @@ static struct cedrus_format cedrus_formats[] = { .pixelformat = V4L2_PIX_FMT_NV12_32L32, .directions = CEDRUS_DECODE_DST, }, + { + .pixelformat = V4L2_PIX_FMT_NV21, + .directions = CEDRUS_DECODE_DST, + .capabilities = CEDRUS_CAPABILITY_UNTILED, + }, + { + .pixelformat = V4L2_PIX_FMT_YUV420, + .directions = CEDRUS_DECODE_DST, + .capabilities = CEDRUS_CAPABILITY_UNTILED, + }, + { + .pixelformat = V4L2_PIX_FMT_YVU420, + .directions = CEDRUS_DECODE_DST, + .capabilities = CEDRUS_CAPABILITY_UNTILED, + }, }; #define CEDRUS_FORMATS_COUNT ARRAY_SIZE(cedrus_formats) @@ -140,6 +155,9 @@ void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) break; case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: /* 16-aligned stride. */ bytesperline = ALIGN(width, 16); diff --git a/drivers/staging/nvec/nvec_power.c b/drivers/staging/nvec/nvec_power.c index e0e67a3eb7222..2faab9fdedef7 100644 --- a/drivers/staging/nvec/nvec_power.c +++ b/drivers/staging/nvec/nvec_power.c @@ -194,7 +194,7 @@ static int nvec_power_bat_notifier(struct notifier_block *nb, break; case MANUFACTURER: memcpy(power->bat_manu, &res->plc, res->length - 2); - power->bat_model[res->length - 2] = '\0'; + power->bat_manu[res->length - 2] = '\0'; break; case MODEL: memcpy(power->bat_model, &res->plc, res->length - 2); diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c index 383a6f7c06f44..b2e7e7267aa49 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ap.c +++ b/drivers/staging/rtl8723bs/core/rtw_ap.c @@ -741,13 +741,8 @@ void start_bss_network(struct adapter *padapter) if (p && ie_len) { pht_info = (struct HT_info_element *)(p + 2); - if (cur_channel > 14) { - if ((pregpriv->bw_mode & 0xf0) > 0) - cbw40_enable = 1; - } else { - if ((pregpriv->bw_mode & 0x0f) > 0) - cbw40_enable = 1; - } + if ((pregpriv->bw_mode & 0x0f) > 0) + cbw40_enable = 1; if ((cbw40_enable) && (pht_info->infos[0] & BIT(2))) { /* switch to the 40M Hz mode */ diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index 437934dd255e9..ef2d92b5588ad 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -1317,9 +1317,6 @@ u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue) /* struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); */ u8 res = _SUCCESS; - /* if (!pwrctrlpriv->bLeisurePs) */ - /* return res; */ - if (enqueue) { ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); if (!ph2c) { diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index 7a74b011dedc2..208373113a62c 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -70,7 +70,7 @@ Efuse_Write1ByteToFakeContent(u16 Offset, u8 Value) * When Who Remark * 11/17/2008 MHC Create Version 0. * - *---------------------------------------------------------------------------*/ + */ void Efuse_PowerSwitch( struct adapter *padapter, @@ -85,6 +85,7 @@ u8 Efuse_CalculateWordCnts(u8 word_en) { u8 word_cnts = 0; + if (!(word_en & BIT(0))) word_cnts++; /* 0 : write enable */ if (!(word_en & BIT(1))) @@ -163,7 +164,7 @@ EFUSE_GetEfuseDefinition( * When Who Remark * 09/23/2008 MHC Copy from WMAC. * - *---------------------------------------------------------------------------*/ + */ u8 EFUSE_Read1Byte( struct adapter *Adapter, @@ -286,18 +287,6 @@ u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoT return bResult; } -u8 -Efuse_WordEnableDataWrite(struct adapter *padapter, - u16 efuse_addr, - u8 word_en, - u8 *data, - bool bPseudoTest) -{ - return padapter->HalFunc.Efuse_WordEnableDataWrite(padapter, efuse_addr, - word_en, data, - bPseudoTest); -} - /*----------------------------------------------------------------------------- * Function: Efuse_ReadAllMap * @@ -313,7 +302,7 @@ Efuse_WordEnableDataWrite(struct adapter *padapter, * When Who Remark * 11/11/2008 MHC Create Version 0. * - *---------------------------------------------------------------------------*/ + */ void Efuse_ReadAllMap( struct adapter *padapter, @@ -350,7 +339,7 @@ void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse, bool bP * When Who Remark * 11/12/2008 MHC Create Version 0. * - *---------------------------------------------------------------------------*/ + */ static void efuse_ShadowRead1Byte(struct adapter *padapter, u16 Offset, u8 *Value) { struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); @@ -396,7 +385,7 @@ static void efuse_ShadowRead4Byte(struct adapter *padapter, u16 Offset, u32 *Val * When Who Remark * 11/13/2008 MHC Create Version 0. * - *---------------------------------------------------------------------------*/ + */ void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType, bool bPseudoTest) { struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); @@ -429,7 +418,7 @@ void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType, bool bPseudoT * When Who Remark * 11/12/2008 MHC Create Version 0. * - *---------------------------------------------------------------------------*/ + */ void EFUSE_ShadowRead(struct adapter *padapter, u8 Type, u16 Offset, u32 *Value) { if (Type == 1) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index 6301dbbcc4720..692d0c2b766d8 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -119,7 +119,7 @@ struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv) pnetwork = NULL; goto exit; } - plist = get_next(&(free_queue->queue)); + plist = get_next(&free_queue->queue); pnetwork = container_of(plist, struct wlan_network, list); @@ -141,7 +141,7 @@ void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwor { unsigned int delta_time; u32 lifetime = SCANQUEUE_LIFETIME; - struct __queue *free_queue = &(pmlmepriv->free_bss_pool); + struct __queue *free_queue = &pmlmepriv->free_bss_pool; if (!pnetwork) return; @@ -161,9 +161,9 @@ void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwor spin_lock_bh(&free_queue->lock); - list_del_init(&(pnetwork->list)); + list_del_init(&pnetwork->list); - list_add_tail(&(pnetwork->list), &(free_queue->queue)); + list_add_tail(&pnetwork->list, &free_queue->queue); spin_unlock_bh(&free_queue->lock); } @@ -171,7 +171,7 @@ void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwor void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork) { - struct __queue *free_queue = &(pmlmepriv->free_bss_pool); + struct __queue *free_queue = &pmlmepriv->free_bss_pool; if (!pnetwork) return; @@ -179,9 +179,9 @@ void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network * if (pnetwork->fixed) return; - list_del_init(&(pnetwork->list)); + list_del_init(&pnetwork->list); - list_add_tail(&(pnetwork->list), get_list_head(free_queue)); + list_add_tail(&pnetwork->list, get_list_head(free_queue)); } /* @@ -287,7 +287,7 @@ void rtw_free_mlme_priv(struct mlme_priv *pmlmepriv) void rtw_free_network_nolock(struct adapter *padapter, struct wlan_network *pnetwork); void rtw_free_network_nolock(struct adapter *padapter, struct wlan_network *pnetwork) { - _rtw_free_network_nolock(&(padapter->mlmepriv), pnetwork); + _rtw_free_network_nolock(&padapter->mlmepriv, pnetwork); rtw_cfg80211_unlink_bss(padapter, pnetwork); } @@ -404,7 +404,7 @@ void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, long rssi_final; /* The rule below is 1/5 for sample value, 4/5 for history value */ - if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&(padapter->mlmepriv.cur_network.network), src, 0)) { + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&padapter->mlmepriv.cur_network.network, src, 0)) { /* Take the recvpriv's value for the connected AP*/ ss_final = padapter->recvpriv.signal_strength; sq_final = padapter->recvpriv.signal_qual; @@ -440,15 +440,15 @@ void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork) { - struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - rtw_bug_check(&(pmlmepriv->cur_network.network), - &(pmlmepriv->cur_network.network), - &(pmlmepriv->cur_network.network), - &(pmlmepriv->cur_network.network)); + rtw_bug_check(&pmlmepriv->cur_network.network, + &pmlmepriv->cur_network.network, + &pmlmepriv->cur_network.network, + &pmlmepriv->cur_network.network); - if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) && (is_same_network(&(pmlmepriv->cur_network.network), pnetwork, 0))) { - update_network(&(pmlmepriv->cur_network.network), pnetwork, adapter, true); + if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) && (is_same_network(&pmlmepriv->cur_network.network, pnetwork, 0))) { + update_network(&pmlmepriv->cur_network.network, pnetwork, adapter, true); rtw_update_protection(adapter, (pmlmepriv->cur_network.network.ies) + sizeof(struct ndis_802_11_fix_ie), pmlmepriv->cur_network.network.ie_length); } @@ -461,8 +461,8 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t { struct list_head *plist, *phead; u32 bssid_ex_sz; - struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); - struct __queue *queue = &(pmlmepriv->scanned_queue); + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct __queue *queue = &pmlmepriv->scanned_queue; struct wlan_network *pnetwork = NULL; struct wlan_network *oldest = NULL; int target_find = 0; @@ -475,7 +475,7 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t rtw_bug_check(pnetwork, pnetwork, pnetwork, pnetwork); - if (is_same_network(&(pnetwork->network), target, feature)) { + if (is_same_network(&pnetwork->network, target, feature)) { target_find = 1; break; } @@ -499,7 +499,7 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t if (!pnetwork) goto exit; - memcpy(&(pnetwork->network), target, get_wlan_bssid_ex_sz(target)); + memcpy(&pnetwork->network, target, get_wlan_bssid_ex_sz(target)); /* variable initialize */ pnetwork->fixed = false; pnetwork->last_scanned = jiffies; @@ -521,7 +521,7 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t bssid_ex_sz = get_wlan_bssid_ex_sz(target); target->length = bssid_ex_sz; - memcpy(&(pnetwork->network), target, bssid_ex_sz); + memcpy(&pnetwork->network, target, bssid_ex_sz); pnetwork->last_scanned = jiffies; @@ -529,7 +529,7 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t if (pnetwork->network.phy_info.signal_quality == 101) pnetwork->network.phy_info.signal_quality = 0; - list_add_tail(&(pnetwork->list), &(queue->queue)); + list_add_tail(&pnetwork->list, &queue->queue); } } else { @@ -553,7 +553,7 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t update_ie = false; } - update_network(&(pnetwork->network), target, adapter, update_ie); + update_network(&pnetwork->network, target, adapter, update_ie); } exit: @@ -629,7 +629,7 @@ void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) { u32 len; struct wlan_bssid_ex *pnetwork; - struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; pnetwork = (struct wlan_bssid_ex *)pbuf; @@ -641,18 +641,18 @@ void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) /* update IBSS_network 's timestamp */ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) { - if (!memcmp(&(pmlmepriv->cur_network.network.mac_address), pnetwork->mac_address, ETH_ALEN)) { + if (!memcmp(&pmlmepriv->cur_network.network.mac_address, pnetwork->mac_address, ETH_ALEN)) { struct wlan_network *ibss_wlan = NULL; memcpy(pmlmepriv->cur_network.network.ies, pnetwork->ies, 8); - spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_lock_bh(&pmlmepriv->scanned_queue.lock); ibss_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->mac_address); if (ibss_wlan) { memcpy(ibss_wlan->network.ies, pnetwork->ies, 8); - spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); goto exit; } - spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); } } @@ -670,7 +670,7 @@ exit: void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) { - struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; spin_lock_bh(&pmlmepriv->lock); if (pmlmepriv->wps_probe_req_ie) { @@ -697,7 +697,7 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); } else { u8 ret = _SUCCESS; - struct wlan_bssid_ex *pdev_network = &(adapter->registrypriv.dev_network); + struct wlan_bssid_ex *pdev_network = &adapter->registrypriv.dev_network; u8 *pibss = adapter->registrypriv.dev_network.mac_address; /* pmlmepriv->fw_state ^= _FW_UNDER_SURVEY;because don't set assoc_timer */ @@ -922,8 +922,8 @@ inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted) void rtw_scan_abort(struct adapter *adapter) { unsigned long start; - struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); - struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; start = jiffies; pmlmeext->scan_abort = true; @@ -1029,8 +1029,8 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str /* ptarget_wlan: found from scanned_queue */ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_network *ptarget_wlan, struct wlan_network *pnetwork) { - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - struct wlan_network *cur_network = &(pmlmepriv->cur_network); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; /* why not use ptarget_wlan?? */ memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.length); @@ -1086,14 +1086,12 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) static u8 __maybe_unused retry; struct sta_info *ptarget_sta = NULL, *pcur_sta = NULL; struct sta_priv *pstapriv = &adapter->stapriv; - struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct wlan_network *pnetwork = (struct wlan_network *)pbuf; - struct wlan_network *cur_network = &(pmlmepriv->cur_network); + struct wlan_network *cur_network = &pmlmepriv->cur_network; struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL; unsigned int the_same_macaddr = false; - rtw_get_encrypt_decrypt_from_registrypriv(adapter); - the_same_macaddr = !memcmp(pnetwork->network.mac_address, cur_network->network.mac_address, ETH_ALEN); pnetwork->network.length = get_wlan_bssid_ex_sz(&pnetwork->network); @@ -1106,7 +1104,7 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0; if (pnetwork->join_res > 0) { - spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_lock_bh(&pmlmepriv->scanned_queue.lock); retry = 0; if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { /* s1. find ptarget_wlan */ @@ -1143,7 +1141,7 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) } else { netdev_dbg(adapter->pnetdev, "Can't find ptarget_wlan when joinbss_event callback\n"); - spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); goto ignore_joinbss_callback; } @@ -1151,7 +1149,7 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork); if (!ptarget_sta) { - spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); goto ignore_joinbss_callback; } } @@ -1169,7 +1167,7 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) timer_delete_sync(&pmlmepriv->assoc_timer); spin_lock_bh(&pmlmepriv->lock); } else { - spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); } } else if (pnetwork->join_res == -4) { rtw_reset_securitypriv(adapter); @@ -1233,9 +1231,9 @@ void rtw_sta_media_status_rpt(struct adapter *adapter, struct sta_info *psta, u3 void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) { struct sta_info *psta; - struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct stassoc_event *pstassoc = (struct stassoc_event *)pbuf; - struct wlan_network *cur_network = &(pmlmepriv->cur_network); + struct wlan_network *cur_network = &pmlmepriv->cur_network; struct wlan_network *ptarget_wlan = NULL; if (rtw_access_ctrl(adapter, pstassoc->macaddr) == false) @@ -1306,12 +1304,12 @@ void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) { if (adapter->stapriv.asoc_sta_count == 2) { - spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_lock_bh(&pmlmepriv->scanned_queue.lock); ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.mac_address); pmlmepriv->cur_network_scanned = ptarget_wlan; if (ptarget_wlan) ptarget_wlan->fixed = true; - spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ rtw_indicate_connect(adapter); } @@ -1329,11 +1327,11 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) struct wlan_network *pwlan = NULL; struct wlan_bssid_ex *pdev_network = NULL; u8 *pibss = NULL; - struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct stadel_event *pstadel = (struct stadel_event *)pbuf; - struct wlan_network *tgt_network = &(pmlmepriv->cur_network); + struct wlan_network *tgt_network = &pmlmepriv->cur_network; struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr); if (psta) @@ -1385,14 +1383,14 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) rtw_free_assoc_resources(adapter, 1); rtw_indicate_disconnect(adapter); - spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_lock_bh(&pmlmepriv->scanned_queue.lock); /* remove the network entry in scanned_queue */ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.mac_address); if (pwlan) { pwlan->fixed = false; rtw_free_network_nolock(adapter, pwlan); } - spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); _rtw_roaming(adapter, roam_target); } @@ -1404,16 +1402,16 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) if (adapter->stapriv.asoc_sta_count == 1) {/* a sta + bc/mc_stainfo (not Ibss_stainfo) */ u8 ret = _SUCCESS; - spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_lock_bh(&pmlmepriv->scanned_queue.lock); /* free old ibss network */ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.mac_address); if (pwlan) { pwlan->fixed = false; rtw_free_network_nolock(adapter, pwlan); } - spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); /* re-create ibss */ - pdev_network = &(adapter->registrypriv.dev_network); + pdev_network = &adapter->registrypriv.dev_network; pibss = adapter->registrypriv.dev_network.mac_address; memcpy(pdev_network, &tgt_network->network, get_wlan_bssid_ex_sz(&tgt_network->network)); @@ -1521,7 +1519,7 @@ void rtw_mlme_reset_auto_scan_int(struct adapter *adapter) { struct mlme_priv *mlme = &adapter->mlmepriv; struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; if (pmlmeinfo->VHT_enable) /* disable auto scan when connect to 11AC AP */ mlme->auto_scan_int_ms = 0; @@ -1662,7 +1660,7 @@ int rtw_select_roaming_candidate(struct mlme_priv *mlme) { int ret = _FAIL; struct list_head *phead; - struct __queue *queue = &(mlme->scanned_queue); + struct __queue *queue = &mlme->scanned_queue; struct wlan_network *pnetwork = NULL; struct wlan_network *candidate = NULL; @@ -1671,7 +1669,7 @@ int rtw_select_roaming_candidate(struct mlme_priv *mlme) return ret; } - spin_lock_bh(&(mlme->scanned_queue.lock)); + spin_lock_bh(&mlme->scanned_queue.lock); phead = get_list_head(queue); list_for_each(mlme->pscanned, phead) { @@ -1695,7 +1693,7 @@ int rtw_select_roaming_candidate(struct mlme_priv *mlme) ret = _SUCCESS; exit: - spin_unlock_bh(&(mlme->scanned_queue.lock)); + spin_unlock_bh(&mlme->scanned_queue.lock); return ret; } @@ -1756,13 +1754,13 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) int ret; struct list_head *phead; struct adapter *adapter; - struct __queue *queue = &(pmlmepriv->scanned_queue); + struct __queue *queue = &pmlmepriv->scanned_queue; struct wlan_network *pnetwork = NULL; struct wlan_network *candidate = NULL; adapter = (struct adapter *)pmlmepriv->nic_hdl; - spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_lock_bh(&pmlmepriv->scanned_queue.lock); if (pmlmepriv->roam_network) { candidate = pmlmepriv->roam_network; @@ -1800,7 +1798,7 @@ candidate_exist: ret = rtw_joinbss_cmd(adapter, candidate); exit: - spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); return ret; } @@ -1808,7 +1806,7 @@ signed int rtw_set_auth(struct adapter *adapter, struct security_priv *psecurity { struct cmd_obj *pcmd; struct setauth_parm *psetauthparm; - struct cmd_priv *pcmdpriv = &(adapter->cmdpriv); + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; signed int res = _SUCCESS; pcmd = rtw_zmalloc(sizeof(struct cmd_obj)); @@ -1845,7 +1843,7 @@ signed int rtw_set_key(struct adapter *adapter, struct security_priv *psecurityp u8 keylen; struct cmd_obj *pcmd; struct setkey_parm *psetkeyparm; - struct cmd_priv *pcmdpriv = &(adapter->cmdpriv); + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; signed int res = _SUCCESS; psetkeyparm = rtw_zmalloc(sizeof(struct setkey_parm)); @@ -1868,11 +1866,11 @@ signed int rtw_set_key(struct adapter *adapter, struct security_priv *psecurityp case _WEP40_: keylen = 5; - memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen); + memcpy(&psetkeyparm->key[0], &psecuritypriv->dot11DefKey[keyid].skey[0], keylen); break; case _WEP104_: keylen = 13; - memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen); + memcpy(&psetkeyparm->key[0], &psecuritypriv->dot11DefKey[keyid].skey[0], keylen); break; case _TKIP_: keylen = 16; @@ -2095,10 +2093,6 @@ void rtw_update_registrypriv_dev_network(struct adapter *adapter) /* pdev_network->ie_length = cpu_to_le32(sz); */ } -void rtw_get_encrypt_decrypt_from_registrypriv(struct adapter *adapter) -{ -} - /* the function is at passive_level */ void rtw_joinbss_reset(struct adapter *padapter) { @@ -2252,13 +2246,8 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ } /* to disable 40M Hz support while gd_bw_40MHz_en = 0 */ - if (channel > 14) { - if ((pregistrypriv->bw_mode & 0xf0) > 0) - cbw40_enable = 1; - } else { - if ((pregistrypriv->bw_mode & 0x0f) > 0) - cbw40_enable = 1; - } + if ((pregistrypriv->bw_mode & 0x0f) > 0) + cbw40_enable = 1; if ((cbw40_enable == 1) && (operation_bw == CHANNEL_WIDTH_40)) { ht_capie.cap_info |= cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH); @@ -2335,7 +2324,7 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe struct ht_priv *phtpriv = &pmlmepriv->htpriv; struct registry_priv *pregistrypriv = &padapter->registrypriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; u8 cbw40_enable = 0; if (!phtpriv->ht_option) @@ -2366,13 +2355,8 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe /* todo: */ } - if (channel > 14) { - if ((pregistrypriv->bw_mode & 0xf0) > 0) - cbw40_enable = 1; - } else { - if ((pregistrypriv->bw_mode & 0x0f) > 0) - cbw40_enable = 1; - } + if ((pregistrypriv->bw_mode & 0x0f) > 0) + cbw40_enable = 1; /* update cur_bwmode & cur_ch_offset */ if ((cbw40_enable) && diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c index 1e9eff01b1aa5..e9f382c280d9b 100644 --- a/drivers/staging/rtl8723bs/core/rtw_security.c +++ b/drivers/staging/rtl8723bs/core/rtw_security.c @@ -868,29 +868,21 @@ static signed int aes_cipher(u8 *key, uint hdrlen, num_blocks, payload_index; u8 pn_vector[6]; - u8 mic_iv[16]; - u8 mic_header1[16]; - u8 mic_header2[16]; - u8 ctr_preload[16]; + u8 mic_iv[16] = {}; + u8 mic_header1[16] = {}; + u8 mic_header2[16] = {}; + u8 ctr_preload[16] = {}; /* Intermediate Buffers */ - u8 chain_buffer[16]; - u8 aes_out[16]; - u8 padded_buffer[16]; + u8 chain_buffer[16] = {}; + u8 aes_out[16] = {}; + u8 padded_buffer[16] = {}; u8 mic[8]; uint frtype = GetFrameType(pframe); uint frsubtype = GetFrameSubType(pframe); frsubtype = frsubtype>>4; - memset((void *)mic_iv, 0, 16); - memset((void *)mic_header1, 0, 16); - memset((void *)mic_header2, 0, 16); - memset((void *)ctr_preload, 0, 16); - memset((void *)chain_buffer, 0, 16); - memset((void *)aes_out, 0, 16); - memset((void *)padded_buffer, 0, 16); - if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) a4_exists = 0; else @@ -1080,15 +1072,15 @@ static signed int aes_decipher(u8 *key, uint hdrlen, num_blocks, payload_index; signed int res = _SUCCESS; u8 pn_vector[6]; - u8 mic_iv[16]; - u8 mic_header1[16]; - u8 mic_header2[16]; - u8 ctr_preload[16]; + u8 mic_iv[16] = {}; + u8 mic_header1[16] = {}; + u8 mic_header2[16] = {}; + u8 ctr_preload[16] = {}; /* Intermediate Buffers */ - u8 chain_buffer[16]; - u8 aes_out[16]; - u8 padded_buffer[16]; + u8 chain_buffer[16] = {}; + u8 aes_out[16] = {}; + u8 padded_buffer[16] = {}; u8 mic[8]; uint frtype = GetFrameType(pframe); @@ -1096,14 +1088,6 @@ static signed int aes_decipher(u8 *key, uint hdrlen, frsubtype = frsubtype>>4; - memset((void *)mic_iv, 0, 16); - memset((void *)mic_header1, 0, 16); - memset((void *)mic_header2, 0, 16); - memset((void *)ctr_preload, 0, 16); - memset((void *)chain_buffer, 0, 16); - memset((void *)aes_out, 0, 16); - memset((void *)padded_buffer, 0, 16); - /* start to decrypt the payload */ num_blocks = (plen-8) / 16; /* plen including LLC, payload_length and mic) */ diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index 73c70b016f009..0c6072d08661a 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -854,13 +854,8 @@ static void bwmode_update_check(struct adapter *padapter, struct ndis_80211_var_ pHT_info = (struct HT_info_element *)pIE->data; - if (pmlmeext->cur_channel > 14) { - if ((pregistrypriv->bw_mode & 0xf0) > 0) - cbw40_enable = 1; - } else { - if ((pregistrypriv->bw_mode & 0x0f) > 0) - cbw40_enable = 1; - } + if ((pregistrypriv->bw_mode & 0x0f) > 0) + cbw40_enable = 1; if ((pHT_info->infos[0] & BIT(2)) && cbw40_enable) { new_bwmode = CHANNEL_WIDTH_40; diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index 026d58b4bd7fe..8c6841f078b47 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -381,7 +381,7 @@ static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame * while (true) { /* IOT action */ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS) && (pattrib->ampdu_en == true) && - (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) { + (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) { pattrib->vcs_mode = CTS_TO_SELF; break; } diff --git a/drivers/staging/rtl8723bs/hal/HalPhyRf.h b/drivers/staging/rtl8723bs/hal/HalPhyRf.h index fdbdd68edf2a6..1e79ab9cb773a 100644 --- a/drivers/staging/rtl8723bs/hal/HalPhyRf.h +++ b/drivers/staging/rtl8723bs/hal/HalPhyRf.h @@ -15,7 +15,6 @@ enum pwrtrack_method { }; typedef void (*FuncSetPwr)(struct dm_odm_t *, enum pwrtrack_method, u8, u8); -typedef void (*FuncIQK)(struct dm_odm_t *, u8, u8, u8); typedef void (*FuncLCK)(struct dm_odm_t *); typedef void (*FuncSwing)(struct dm_odm_t *, u8 **, u8 **, u8 **, u8 **); @@ -27,7 +26,6 @@ struct txpwrtrack_cfg { u8 RfPathCount; u32 ThermalRegAddr; FuncSetPwr ODM_TxPwrTrackSetPwr; - FuncIQK DoIQK; FuncLCK PHY_LCCalibrate; FuncSwing GetDeltaSwingTable; }; diff --git a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c index 81149ab81904c..34692cca33f58 100644 --- a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c +++ b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c @@ -142,15 +142,6 @@ static void setCCKFilterCoefficient(struct dm_odm_t *pDM_Odm, u8 CCKSwingIndex) } } -void DoIQK_8723B( - struct dm_odm_t *pDM_Odm, - u8 DeltaThermalIndex, - u8 ThermalValue, - u8 Threshold -) -{ -} - /*----------------------------------------------------------------------------- * Function: odm_TxPwrTrackSetPwr88E() * @@ -353,7 +344,6 @@ void ConfigureTxpowerTrack_8723B(struct txpwrtrack_cfg *pConfig) pConfig->ThermalRegAddr = RF_T_METER_8723B; pConfig->ODM_TxPwrTrackSetPwr = ODM_TxPwrTrackSetPwr_8723B; - pConfig->DoIQK = DoIQK_8723B; pConfig->PHY_LCCalibrate = PHY_LCCalibrate_8723B; pConfig->GetDeltaSwingTable = GetDeltaSwingTable_8723B; } diff --git a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.h b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.h index 775095ad0921c..c83442917f9db 100644 --- a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.h +++ b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.h @@ -18,13 +18,6 @@ void ConfigureTxpowerTrack_8723B(struct txpwrtrack_cfg *pConfig); -void DoIQK_8723B( - struct dm_odm_t *pDM_Odm, - u8 DeltaThermalIndex, - u8 ThermalValue, - u8 Threshold -); - void ODM_TxPwrTrackSetPwr_8723B( struct dm_odm_t *pDM_Odm, enum pwrtrack_method Method, diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c index d91e2461fd7e4..07e9d34236517 100644 --- a/drivers/staging/rtl8723bs/hal/hal_com.c +++ b/drivers/staging/rtl8723bs/hal/hal_com.c @@ -569,19 +569,12 @@ void rtw_hal_update_sta_rate_mask(struct adapter *padapter, struct sta_info *pst psta->init_rate = get_highest_rate_idx(tx_ra_bitmap)&0x3f; } -void hw_var_port_switch(struct adapter *adapter) -{ -} - void SetHwReg(struct adapter *adapter, u8 variable, u8 *val) { struct hal_com_data *hal_data = GET_HAL_DATA(adapter); struct dm_odm_t *odm = &(hal_data->odmpriv); switch (variable) { - case HW_VAR_PORT_SWITCH: - hw_var_port_switch(adapter); - break; case HW_VAR_INIT_RTS_RATE: rtw_warn_on(1); break; diff --git a/drivers/staging/rtl8723bs/hal/hal_intf.c b/drivers/staging/rtl8723bs/hal/hal_intf.c index 0db8f623b8059..961b0563951d2 100644 --- a/drivers/staging/rtl8723bs/hal/hal_intf.c +++ b/drivers/staging/rtl8723bs/hal/hal_intf.c @@ -38,10 +38,6 @@ void rtw_hal_dm_init(struct adapter *padapter) rtl8723b_init_dm_priv(padapter); } -void rtw_hal_dm_deinit(struct adapter *padapter) -{ -} - static void rtw_hal_init_opmode(struct adapter *padapter) { enum ndis_802_11_network_infrastructure networkType = Ndis802_11InfrastructureMax; @@ -77,8 +73,6 @@ uint rtw_hal_init(struct adapter *padapter) if (padapter->registrypriv.notch_filter == 1) rtw_hal_notch_filter(padapter, 1); - rtw_hal_reset_security_engine(padapter); - rtw_sec_restore_wep_key(dvobj->padapters); init_hw_mlme_ext(padapter); @@ -133,8 +127,7 @@ u8 rtw_hal_get_def_var(struct adapter *padapter, enum hal_def_variable eVariable void rtw_hal_set_odm_var(struct adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet) { - if (padapter->HalFunc.SetHalODMVarHandler) - padapter->HalFunc.SetHalODMVarHandler(padapter, eVariable, pValue1, bSet); + SetHalODMVar(padapter, eVariable, pValue1, bSet); } void rtw_hal_enable_interrupt(struct adapter *padapter) @@ -290,21 +283,12 @@ void beacon_timing_control(struct adapter *padapter) s32 rtw_hal_xmit_thread_handler(struct adapter *padapter) { - if (padapter->HalFunc.xmit_thread_handler) - return padapter->HalFunc.xmit_thread_handler(padapter); - return _FAIL; + return rtl8723bs_xmit_buf_handler(padapter); } void rtw_hal_notch_filter(struct adapter *adapter, bool enable) { - if (adapter->HalFunc.hal_notch_filter) - adapter->HalFunc.hal_notch_filter(adapter, enable); -} - -void rtw_hal_reset_security_engine(struct adapter *adapter) -{ - if (adapter->HalFunc.hal_reset_security_engine) - adapter->HalFunc.hal_reset_security_engine(adapter); + hal_notch_filter_8723b(adapter, enable); } bool rtw_hal_c2h_valid(struct adapter *adapter, u8 *buf) @@ -314,16 +298,12 @@ bool rtw_hal_c2h_valid(struct adapter *adapter, u8 *buf) s32 rtw_hal_c2h_handler(struct adapter *adapter, u8 *c2h_evt) { - s32 ret = _FAIL; - - if (adapter->HalFunc.c2h_handler) - ret = adapter->HalFunc.c2h_handler(adapter, c2h_evt); - return ret; + return c2h_handler_8723b(adapter, c2h_evt); } c2h_id_filter rtw_hal_c2h_id_filter_ccx(struct adapter *adapter) { - return adapter->HalFunc.c2h_id_filter_ccx; + return c2h_id_filter_ccx_8723b; } s32 rtw_hal_macid_sleep(struct adapter *padapter, u32 macid) @@ -356,10 +336,5 @@ s32 rtw_hal_macid_wakeup(struct adapter *padapter, u32 macid) s32 rtw_hal_fill_h2c_cmd(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer) { - s32 ret = _FAIL; - - if (padapter->HalFunc.fill_h2c_cmd) - ret = padapter->HalFunc.fill_h2c_cmd(padapter, ElementID, CmdLen, pCmdBuffer); - - return ret; + return FillH2CCmd8723B(padapter, ElementID, CmdLen, pCmdBuffer); } diff --git a/drivers/staging/rtl8723bs/hal/odm.c b/drivers/staging/rtl8723bs/hal/odm.c index 8d6131f0ad47d..ba85efb30db25 100644 --- a/drivers/staging/rtl8723bs/hal/odm.c +++ b/drivers/staging/rtl8723bs/hal/odm.c @@ -315,14 +315,6 @@ static void odm_CommonInfoSelfUpdate(struct dm_odm_t *pDM_Odm) pDM_Odm->bOneEntryOnly = false; } -static void odm_CmnInfoInit_Debug(struct dm_odm_t *pDM_Odm) -{ -} - -static void odm_BasicDbgMessage(struct dm_odm_t *pDM_Odm) -{ -} - /* 3 ============================================================ */ /* 3 RATR MASK */ /* 3 ============================================================ */ @@ -735,7 +727,6 @@ void ODM_DMInit(struct dm_odm_t *pDM_Odm) { odm_CommonInfoSelfInit(pDM_Odm); - odm_CmnInfoInit_Debug(pDM_Odm); odm_DIGInit(pDM_Odm); odm_NHMCounterStatisticsInit(pDM_Odm); odm_AdaptivityInit(pDM_Odm); @@ -761,7 +752,6 @@ void ODM_DMInit(struct dm_odm_t *pDM_Odm) void ODM_DMWatchdog(struct dm_odm_t *pDM_Odm) { odm_CommonInfoSelfUpdate(pDM_Odm); - odm_BasicDbgMessage(pDM_Odm); odm_FalseAlarmCounterStatistics(pDM_Odm); odm_NHMCounterStatistics(pDM_Odm); diff --git a/drivers/staging/rtl8723bs/hal/odm_DIG.c b/drivers/staging/rtl8723bs/hal/odm_DIG.c index 1e2946a23bebd..f10427abd8490 100644 --- a/drivers/staging/rtl8723bs/hal/odm_DIG.c +++ b/drivers/staging/rtl8723bs/hal/odm_DIG.c @@ -370,7 +370,6 @@ void odm_DIGInit(void *pDM_VOID) pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; - } diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c index 56526056dd1d2..63c4ebe9df129 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c @@ -57,13 +57,11 @@ s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmd if (mutex_lock_interruptible(&(adapter_to_dvobj(padapter)->h2c_fwcmd_mutex))) return ret; - if (!pCmdBuffer) { + if (!pCmdBuffer) goto exit; - } - if (CmdLen > RTL8723B_MAX_CMD_LEN) { + if (CmdLen > RTL8723B_MAX_CMD_LEN) goto exit; - } if (padapter->bSurpriseRemoved) goto exit; @@ -287,15 +285,6 @@ static void ConstructNullFunctionData( *pLength = pktlen; } -/* - * To check if reserved page content is destroyed by beacon because beacon - * is too large. - */ -/* 2010.06.23. Added by tynli. */ -void CheckFwRsvdPageContent(struct adapter *Adapter) -{ -} - static void rtl8723b_set_FwRsvdPage_cmd(struct adapter *padapter, struct rsvdpage_loc *rsvdpageloc) { u8 u1H2CRsvdPageParm[H2C_RSVDPAGE_LOC_LEN] = {0}; @@ -309,10 +298,6 @@ static void rtl8723b_set_FwRsvdPage_cmd(struct adapter *padapter, struct rsvdpag FillH2CCmd8723B(padapter, H2C_8723B_RSVD_PAGE, H2C_RSVDPAGE_LOC_LEN, u1H2CRsvdPageParm); } -static void rtl8723b_set_FwAoacRsvdPage_cmd(struct adapter *padapter, struct rsvdpage_loc *rsvdpageloc) -{ -} - void rtl8723b_set_FwMediaStatusRpt_cmd(struct adapter *padapter, u8 mstatus, u8 macid) { u8 u1H2CMediaStatusRptParm[H2C_MEDIA_STATUS_RPT_LEN] = {0}; @@ -614,12 +599,9 @@ static void rtl8723b_set_FwRsvdPagePkt( dump_mgntframe_and_wait(padapter, pcmdframe, 100); } - if (check_fwstate(pmlmepriv, _FW_LINKED)) { + if (check_fwstate(pmlmepriv, _FW_LINKED)) rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc); - rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); - } else { - rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); - } + return; error: @@ -885,7 +867,6 @@ static void SetFwRsvdPagePkt_BTCoex(struct adapter *padapter) dump_mgntframe_and_wait(padapter, pcmdframe, 100); rtl8723b_set_FwRsvdPage_cmd(padapter, &RsvdPageLoc); - rtl8723b_set_FwAoacRsvdPage_cmd(padapter, &RsvdPageLoc); return; diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c b/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c index d1c875cf8e6d2..928226679ab45 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c @@ -12,9 +12,6 @@ /* Global var */ -static void dm_CheckStatistics(struct adapter *Adapter) -{ -} /* */ /* functions */ /* */ @@ -144,10 +141,6 @@ void rtl8723b_HalDmWatchDog(struct adapter *Adapter) (hw_init_completed == true) && ((!fw_current_in_ps_mode) && bFwPSAwake) ) { - /* */ - /* Calculate Tx/Rx statistics. */ - /* */ - dm_CheckStatistics(Adapter); rtw_hal_check_rxfifo_full(Adapter); } diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 893cab0532ed0..1608bc71bd710 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -1077,71 +1077,6 @@ u16 Hal_EfuseGetCurrentSize( return ret; } -static u8 Hal_EfuseWordEnableDataWrite( - struct adapter *padapter, - u16 efuse_addr, - u8 word_en, - u8 *data, - bool bPseudoTest -) -{ - u16 tmpaddr = 0; - u16 start_addr = efuse_addr; - u8 badworden = 0x0F; - u8 tmpdata[PGPKT_DATA_SIZE]; - - memset(tmpdata, 0xFF, PGPKT_DATA_SIZE); - - if (!(word_en & BIT(0))) { - tmpaddr = start_addr; - efuse_OneByteWrite(padapter, start_addr++, data[0], bPseudoTest); - efuse_OneByteWrite(padapter, start_addr++, data[1], bPseudoTest); - - efuse_OneByteRead(padapter, tmpaddr, &tmpdata[0], bPseudoTest); - efuse_OneByteRead(padapter, tmpaddr+1, &tmpdata[1], bPseudoTest); - if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) { - badworden &= (~BIT(0)); - } - } - if (!(word_en & BIT(1))) { - tmpaddr = start_addr; - efuse_OneByteWrite(padapter, start_addr++, data[2], bPseudoTest); - efuse_OneByteWrite(padapter, start_addr++, data[3], bPseudoTest); - - efuse_OneByteRead(padapter, tmpaddr, &tmpdata[2], bPseudoTest); - efuse_OneByteRead(padapter, tmpaddr+1, &tmpdata[3], bPseudoTest); - if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) { - badworden &= (~BIT(1)); - } - } - - if (!(word_en & BIT(2))) { - tmpaddr = start_addr; - efuse_OneByteWrite(padapter, start_addr++, data[4], bPseudoTest); - efuse_OneByteWrite(padapter, start_addr++, data[5], bPseudoTest); - - efuse_OneByteRead(padapter, tmpaddr, &tmpdata[4], bPseudoTest); - efuse_OneByteRead(padapter, tmpaddr+1, &tmpdata[5], bPseudoTest); - if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) { - badworden &= (~BIT(2)); - } - } - - if (!(word_en & BIT(3))) { - tmpaddr = start_addr; - efuse_OneByteWrite(padapter, start_addr++, data[6], bPseudoTest); - efuse_OneByteWrite(padapter, start_addr++, data[7], bPseudoTest); - - efuse_OneByteRead(padapter, tmpaddr, &tmpdata[6], bPseudoTest); - efuse_OneByteRead(padapter, tmpaddr+1, &tmpdata[7], bPseudoTest); - if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) { - badworden &= (~BIT(3)); - } - } - - return badworden; -} - static struct hal_version ReadChipVersion8723B(struct adapter *padapter) { u32 value32; @@ -1261,8 +1196,6 @@ static void StopTxBeacon(struct adapter *padapter) rtw_write8(padapter, REG_TBTT_PROHIBIT+1, 0x64); pHalData->RegReg542 &= ~BIT(0); rtw_write8(padapter, REG_TBTT_PROHIBIT+2, pHalData->RegReg542); - - CheckFwRsvdPageContent(padapter); /* 2010.06.23. Added by tynli. */ } static void _BeaconFunctionEnable(struct adapter *padapter, u8 Enable, u8 Linked) @@ -1332,17 +1265,7 @@ void rtl8723b_SetBeaconRelatedRegisters(struct adapter *padapter) rtw_write8(padapter, bcn_ctrl_reg, val8); } -static void rtl8723b_SetHalODMVar( - struct adapter *Adapter, - enum hal_odm_variable eVariable, - void *pValue1, - bool bSet -) -{ - SetHalODMVar(Adapter, eVariable, pValue1, bSet); -} - -static void hal_notch_filter_8723b(struct adapter *adapter, bool enable) +void hal_notch_filter_8723b(struct adapter *adapter, bool enable) { if (enable) rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) | BIT1); @@ -1387,23 +1310,6 @@ void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_level) pdmpriv->INIDATA_RATE[mac_id] = psta->init_rate; } - -void rtl8723b_set_hal_ops(struct hal_ops *pHalFunc) -{ - /* Efuse related function */ - pHalFunc->Efuse_WordEnableDataWrite = &Hal_EfuseWordEnableDataWrite; - - pHalFunc->SetHalODMVarHandler = &rtl8723b_SetHalODMVar; - - pHalFunc->xmit_thread_handler = &hal_xmit_handler; - pHalFunc->hal_notch_filter = &hal_notch_filter_8723b; - - pHalFunc->c2h_handler = c2h_handler_8723b; - pHalFunc->c2h_id_filter_ccx = c2h_id_filter_ccx_8723b; - - pHalFunc->fill_h2c_cmd = &FillH2CCmd8723B; -} - void rtl8723b_InitAntenna_Selection(struct adapter *padapter) { u8 val; @@ -3185,7 +3091,7 @@ void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) break; case HW_VAR_CHK_HI_QUEUE_EMPTY: val16 = rtw_read16(padapter, REG_TXPKT_EMPTY); - *val = (val16 & BIT(10)) ? true:false; + *val = (val16 & BIT(10)) ? true : false; break; default: GetHwReg(padapter, variable, val); diff --git a/drivers/staging/rtl8723bs/hal/sdio_halinit.c b/drivers/staging/rtl8723bs/hal/sdio_halinit.c index af9a2b068796a..73561a63401ed 100644 --- a/drivers/staging/rtl8723bs/hal/sdio_halinit.c +++ b/drivers/staging/rtl8723bs/hal/sdio_halinit.c @@ -1094,10 +1094,6 @@ static void _ReadPROMContent(struct adapter *padapter) _ReadEfuseInfo8723BS(padapter); } -static void _InitOtherVariable(struct adapter *Adapter) -{ -} - /* */ /* Description: */ /* Read HW adapter information by E-Fuse or EEPROM according CR9346 reported. */ @@ -1122,7 +1118,6 @@ static s32 _ReadAdapterInfo8723BS(struct adapter *padapter) _EfuseCellSel(padapter); _ReadRFType(padapter); _ReadPROMContent(padapter); - _InitOtherVariable(padapter); if (!padapter->hw_init_completed) { rtw_write8(padapter, 0x67, 0x00); /* for BT, Switch Ant control to BT */ @@ -1251,11 +1246,3 @@ u8 SetHalDefVar8723BSDIO(struct adapter *Adapter, enum hal_def_variable eVariabl { return SetHalDefVar8723B(Adapter, eVariable, pValue); } - -void rtl8723bs_set_hal_ops(struct adapter *padapter) -{ - struct hal_ops *pHalFunc = &padapter->HalFunc; - - rtl8723b_set_hal_ops(pHalFunc); - -} diff --git a/drivers/staging/rtl8723bs/include/basic_types.h b/drivers/staging/rtl8723bs/include/basic_types.h index 57bb717327ce0..24626e65fc7f8 100644 --- a/drivers/staging/rtl8723bs/include/basic_types.h +++ b/drivers/staging/rtl8723bs/include/basic_types.h @@ -163,7 +163,7 @@ ( \ LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \ ((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \ - ); + ) #define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \ *((u8 *)(__pstart)) = EF1BYTE \ diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h index 7b0e824e05a9a..080c321665c07 100644 --- a/drivers/staging/rtl8723bs/include/drv_types.h +++ b/drivers/staging/rtl8723bs/include/drv_types.h @@ -350,7 +350,6 @@ struct adapter { void *HalData; u32 hal_data_sz; - struct hal_ops HalFunc; s32 bDriverStopped; s32 bSurpriseRemoved; diff --git a/drivers/staging/rtl8723bs/include/hal_com.h b/drivers/staging/rtl8723bs/include/hal_com.h index 258a74076dd9d..7ea9ee2b39758 100644 --- a/drivers/staging/rtl8723bs/include/hal_com.h +++ b/drivers/staging/rtl8723bs/include/hal_com.h @@ -134,8 +134,6 @@ s32 c2h_evt_read_88xx(struct adapter *adapter, u8 *buf); u8 rtw_get_mgntframe_raid(struct adapter *adapter, unsigned char network_type); void rtw_hal_update_sta_rate_mask(struct adapter *padapter, struct sta_info *psta); -void hw_var_port_switch(struct adapter *adapter); - void SetHwReg(struct adapter *padapter, u8 variable, u8 *val); void GetHwReg(struct adapter *padapter, u8 variable, u8 *val); void rtw_hal_check_rxfifo_full(struct adapter *adapter); diff --git a/drivers/staging/rtl8723bs/include/hal_intf.h b/drivers/staging/rtl8723bs/include/hal_intf.h index 85de862823c24..67d51e55bd44b 100644 --- a/drivers/staging/rtl8723bs/include/hal_intf.h +++ b/drivers/staging/rtl8723bs/include/hal_intf.h @@ -160,20 +160,6 @@ enum hal_intf_ps_func { typedef s32 (*c2h_id_filter)(u8 *c2h_evt); -struct hal_ops { - void (*SetHalODMVarHandler)(struct adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet); - - u8 (*Efuse_WordEnableDataWrite)(struct adapter *padapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest); - - s32 (*xmit_thread_handler)(struct adapter *padapter); - void (*hal_notch_filter)(struct adapter *adapter, bool enable); - void (*hal_reset_security_engine)(struct adapter *adapter); - s32 (*c2h_handler)(struct adapter *padapter, u8 *c2h_evt); - c2h_id_filter c2h_id_filter_ccx; - - s32 (*fill_h2c_cmd)(struct adapter *, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer); -}; - #define RF_CHANGE_BY_INIT 0 #define RF_CHANGE_BY_IPS BIT28 #define RF_CHANGE_BY_PS BIT29 @@ -200,7 +186,6 @@ void rtw_hal_def_value_init(struct adapter *padapter); void rtw_hal_free_data(struct adapter *padapter); void rtw_hal_dm_init(struct adapter *padapter); -void rtw_hal_dm_deinit(struct adapter *padapter); uint rtw_hal_init(struct adapter *padapter); uint rtw_hal_deinit(struct adapter *padapter); @@ -263,7 +248,6 @@ void rtw_hal_dm_watchdog_in_lps(struct adapter *padapter); s32 rtw_hal_xmit_thread_handler(struct adapter *padapter); void rtw_hal_notch_filter(struct adapter *adapter, bool enable); -void rtw_hal_reset_security_engine(struct adapter *adapter); bool rtw_hal_c2h_valid(struct adapter *adapter, u8 *buf); s32 rtw_hal_c2h_handler(struct adapter *adapter, u8 *c2h_evt); @@ -287,4 +271,5 @@ void Hal_ReadEFuse(struct adapter *padapter, u8 efuseType, u16 _offset, void Hal_GetEfuseDefinition(struct adapter *padapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest); u16 Hal_EfuseGetCurrentSize(struct adapter *padapter, u8 efuseType, bool bPseudoTest); +void hal_notch_filter_8723b(struct adapter *adapter, bool enable); #endif /* __HAL_INTF_H__ */ diff --git a/drivers/staging/rtl8723bs/include/ioctl_cfg80211.h b/drivers/staging/rtl8723bs/include/ioctl_cfg80211.h index 993a7b3c3d22b..753009b074511 100644 --- a/drivers/staging/rtl8723bs/include/ioctl_cfg80211.h +++ b/drivers/staging/rtl8723bs/include/ioctl_cfg80211.h @@ -94,6 +94,7 @@ void rtw_cfg80211_init_wiphy(struct adapter *padapter); void rtw_cfg80211_unlink_bss(struct adapter *padapter, struct wlan_network *pnetwork); void rtw_cfg80211_surveydone_event_callback(struct adapter *padapter); +int rtw_ieee80211_channel_to_frequency(int chan); struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wlan_network *pnetwork); int rtw_cfg80211_check_bss(struct adapter *padapter); void rtw_cfg80211_ibss_indicate_connect(struct adapter *padapter); diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_cmd.h b/drivers/staging/rtl8723bs/include/rtl8723b_cmd.h index dbcf01bbf0510..6b2d79e19088e 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_cmd.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_cmd.h @@ -175,11 +175,8 @@ void rtl8723b_set_FwMediaStatusRpt_cmd(struct adapter *padapter, u8 mstatus, u8 void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus); void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter); -void CheckFwRsvdPageContent(struct adapter *padapter); - void rtl8723b_set_FwPwrModeInIPS_cmd(struct adapter *padapter, u8 cmd_param); s32 FillH2CCmd8723B(struct adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer); -#define FillH2CCmd FillH2CCmd8723B #endif diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_hal.h b/drivers/staging/rtl8723bs/include/rtl8723b_hal.h index a4a14474c35d8..40ff96d3cf748 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_hal.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_hal.h @@ -223,7 +223,6 @@ void Hal_EfuseParseVoltage_8723B(struct adapter *padapter, u8 *hwinfo, void C2HPacketHandler_8723B(struct adapter *padapter, u8 *pbuffer, u16 length); -void rtl8723b_set_hal_ops(struct hal_ops *pHalFunc); void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val); void GetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val); u8 SetHalDefVar8723B(struct adapter *padapter, enum hal_def_variable variable, diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h b/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h index ac4ca7e05b9bf..ddf868c7899ba 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h @@ -414,7 +414,6 @@ s32 rtl8723bs_mgnt_xmit(struct adapter *padapter, struct xmit_frame *pmgntframe) s32 rtl8723bs_hal_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe); s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter); int rtl8723bs_xmit_thread(void *context); -#define hal_xmit_handler rtl8723bs_xmit_buf_handler u8 BWMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib); u8 SCMapping_8723B(struct adapter *Adapter, struct pkt_attrib *pattrib); diff --git a/drivers/staging/rtl8723bs/include/rtw_efuse.h b/drivers/staging/rtl8723bs/include/rtw_efuse.h index d6ea8a4a856f1..669565fa1c691 100644 --- a/drivers/staging/rtl8723bs/include/rtw_efuse.h +++ b/drivers/staging/rtl8723bs/include/rtw_efuse.h @@ -96,7 +96,6 @@ u8 efuse_OneByteRead(struct adapter *padapter, u16 addr, u8 *data, bool bPseudo u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoTest); void Efuse_PowerSwitch(struct adapter *padapter, u8 bWrite, u8 PwrState); -u8 Efuse_WordEnableDataWrite(struct adapter *padapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest); u8 EFUSE_Read1Byte(struct adapter *padapter, u16 Address); void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType, bool bPseudoTest); diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme.h b/drivers/staging/rtl8723bs/include/rtw_mlme.h index e665479babc25..3cf68b85eb327 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme.h @@ -341,8 +341,6 @@ extern void rtw_init_registrypriv_dev_network(struct adapter *adapter); extern void rtw_update_registrypriv_dev_network(struct adapter *adapter); -extern void rtw_get_encrypt_decrypt_from_registrypriv(struct adapter *adapter); - extern void _rtw_join_timeout_handler(struct timer_list *t); extern void rtw_scan_timeout_handler(struct timer_list *t); diff --git a/drivers/staging/rtl8723bs/include/sdio_hal.h b/drivers/staging/rtl8723bs/include/sdio_hal.h index 024acf9b530da..6538253765f12 100644 --- a/drivers/staging/rtl8723bs/include/sdio_hal.h +++ b/drivers/staging/rtl8723bs/include/sdio_hal.h @@ -11,6 +11,4 @@ u8 sd_int_isr(struct adapter *padapter); void sd_int_dpc(struct adapter *padapter); void rtw_set_hal_ops(struct adapter *padapter); -void rtl8723bs_set_hal_ops(struct adapter *padapter); - #endif /* __SDIO_HAL_H__ */ diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 7fcc46a0bb48f..ac3d085808e97 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -192,14 +192,14 @@ rtw_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { }, }; -static int rtw_ieee80211_channel_to_frequency(int chan, int band) +int rtw_ieee80211_channel_to_frequency(int chan) { - if (band == NL80211_BAND_2GHZ) { - if (chan == 14) - return 2484; - else if (chan < 14) - return 2407 + chan * 5; - } + /* NL80211_BAND_2GHZ */ + if (chan == 14) + return 2484; + + if (chan < 14) + return 2407 + chan * 5; return 0; /* not supported */ } @@ -266,7 +266,7 @@ struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wl /* spin_unlock_bh(&pwdev_priv->scan_req_lock); */ channel = pnetwork->network.configuration.ds_config; - freq = rtw_ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); + freq = rtw_ieee80211_channel_to_frequency(channel); notify_channel = ieee80211_get_channel(wiphy, freq); @@ -340,7 +340,7 @@ int rtw_cfg80211_check_bss(struct adapter *padapter) if (!(pnetwork) || !(padapter->rtw_wdev)) return false; - freq = rtw_ieee80211_channel_to_frequency(pnetwork->configuration.ds_config, NL80211_BAND_2GHZ); + freq = rtw_ieee80211_channel_to_frequency(pnetwork->configuration.ds_config); notify_channel = ieee80211_get_channel(padapter->rtw_wdev->wiphy, freq); bss = cfg80211_get_bss(padapter->rtw_wdev->wiphy, notify_channel, @@ -440,7 +440,7 @@ check_bss: u16 channel = cur_network->network.configuration.ds_config; struct cfg80211_roam_info roam_info = {}; - freq = rtw_ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); + freq = rtw_ieee80211_channel_to_frequency(channel); notify_channel = ieee80211_get_channel(wiphy, freq); @@ -1298,7 +1298,8 @@ exit: return ret; } -static int cfg80211_rtw_set_wiphy_params(struct wiphy *wiphy, u32 changed) +static int cfg80211_rtw_set_wiphy_params(struct wiphy *wiphy, int radio_idx, + u32 changed) { return 0; } @@ -1795,7 +1796,7 @@ static int cfg80211_rtw_disconnect(struct wiphy *wiphy, struct net_device *ndev, } static int cfg80211_rtw_set_txpower(struct wiphy *wiphy, - struct wireless_dev *wdev, + struct wireless_dev *wdev, int radio_idx, enum nl80211_tx_power_setting type, int mbm) { return 0; @@ -1803,6 +1804,7 @@ static int cfg80211_rtw_set_txpower(struct wiphy *wiphy, static int cfg80211_rtw_get_txpower(struct wiphy *wiphy, struct wireless_dev *wdev, + int radio_idx, unsigned int link_id, int *dbm) { *dbm = (12); @@ -1976,7 +1978,7 @@ static int cfg80211_rtw_get_channel(struct wiphy *wiphy, struct wireless_dev *wd if (!channel) return -ENODATA; - freq = rtw_ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); + freq = rtw_ieee80211_channel_to_frequency(channel); chan = ieee80211_get_channel(adapter->rtw_wdev->wiphy, freq); @@ -2456,7 +2458,7 @@ void rtw_cfg80211_rx_action(struct adapter *adapter, u8 *frame, uint frame_len, rtw_action_frame_parse(frame, frame_len, &category, &action); - freq = rtw_ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ); + freq = rtw_ieee80211_channel_to_frequency(channel); rtw_cfg80211_rx_mgmt(adapter, freq, 0, frame, frame_len, GFP_ATOMIC); } diff --git a/drivers/staging/rtl8723bs/os_dep/os_intfs.c b/drivers/staging/rtl8723bs/os_dep/os_intfs.c index 0248dff8f2aa5..6ca6dc5488057 100644 --- a/drivers/staging/rtl8723bs/os_dep/os_intfs.c +++ b/drivers/staging/rtl8723bs/os_dep/os_intfs.c @@ -99,8 +99,6 @@ MODULE_PARM_DESC(rtw_ant_num, "Antenna number setting"); static int rtw_antdiv_cfg = 1; /* 0:OFF , 1:ON, 2:decide by Efuse config */ static int rtw_antdiv_type; /* 0:decide by efuse 1: for 88EE, 1Tx and 1RxCG are diversity.(2 Ant with SPDT), 2: for 88EE, 1Tx and 2Rx are diversity.(2 Ant, Tx and RxCG are both on aux port, RxCS is on main port), 3: for 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) */ - - static int rtw_hw_wps_pbc; int rtw_mc2u_disable; @@ -523,7 +521,6 @@ static void rtw_init_default_value(struct adapter *padapter) pmlmepriv->htpriv.ampdu_enable = false;/* set to disabled */ /* security_priv */ - /* rtw_get_encrypt_decrypt_from_registrypriv(padapter); */ psecuritypriv->binstallGrpkey = _FAIL; psecuritypriv->sw_encrypt = pregistrypriv->software_encrypt; psecuritypriv->sw_decrypt = pregistrypriv->software_decrypt; @@ -627,7 +624,6 @@ void rtw_reset_drv_sw(struct adapter *padapter) padapter->mlmeextpriv.sitesurvey_res.state = SCAN_DISABLE; rtw_set_signal_stat_timer(&padapter->recvpriv); - } @@ -709,9 +705,6 @@ void rtw_cancel_all_timer(struct adapter *padapter) rtw_clear_scan_deny(padapter); timer_delete_sync(&padapter->recvpriv.signal_stat_timer); - - /* cancel dm timer */ - rtw_hal_dm_deinit(padapter); } u8 rtw_free_drv_sw(struct adapter *padapter) @@ -922,7 +915,7 @@ static int pm_netdev_open(struct net_device *pnetdev, u8 bnormal) mutex_unlock(&(adapter_to_dvobj(padapter)->hw_init_mutex)); } } else { - status = (_SUCCESS == ips_netdrv_open(padapter)) ? (0) : (-1); + status = (ips_netdrv_open(padapter) == _SUCCESS) ? (0) : (-1); } return status; @@ -1112,7 +1105,7 @@ void rtw_suspend_common(struct adapter *padapter) if ((!padapter->bup) || (padapter->bDriverStopped) || (padapter->bSurpriseRemoved)) { pdbgpriv->dbg_suspend_error_cnt++; - goto exit; + return; } rtw_ps_deny(padapter, PS_DENY_SUSPEND); @@ -1134,10 +1127,6 @@ void rtw_suspend_common(struct adapter *padapter) netdev_dbg(padapter->pnetdev, "rtw suspend success in %d ms\n", jiffies_to_msecs(jiffies - start_time)); - -exit: - - return; } static int rtw_resume_process_normal(struct adapter *padapter) @@ -1211,9 +1200,9 @@ int rtw_resume_common(struct adapter *padapter) hal_btcoex_SuspendNotify(padapter, 0); - if (pwrpriv) { + if (pwrpriv) pwrpriv->bInSuspend = false; - } + netdev_dbg(padapter->pnetdev, "%s:%d in %d ms\n", __func__, ret, jiffies_to_msecs(jiffies - start_time)); diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c index 5a7238e661ffb..f3caaa857c864 100644 --- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c +++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c @@ -216,8 +216,6 @@ void rtw_set_hal_ops(struct adapter *padapter) { /* alloc memory for HAL DATA */ rtw_hal_data_init(padapter); - - rtl8723bs_set_hal_ops(padapter); } static void sd_intf_start(struct adapter *padapter) @@ -289,7 +287,7 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct rtw_hal_chip_configure(padapter); - hal_btcoex_Initialize((void *) padapter); + hal_btcoex_Initialize((void *)padapter); /* 3 6. read efuse/eeprom data */ rtw_hal_read_chip_info(padapter); diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c b/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c index 4a7c0c9cc7ef4..5dc00e9117ae5 100644 --- a/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/sdio_ops_linux.c @@ -305,7 +305,6 @@ void sd_write32(struct intf_hdl *pintfhdl, u32 addr, u32 v, s32 *err) } } } - } } diff --git a/drivers/staging/rtl8723bs/os_dep/wifi_regd.c b/drivers/staging/rtl8723bs/os_dep/wifi_regd.c index dbd4bf5313390..f9c4d487badf0 100644 --- a/drivers/staging/rtl8723bs/os_dep/wifi_regd.c +++ b/drivers/staging/rtl8723bs/os_dep/wifi_regd.c @@ -41,17 +41,6 @@ static const struct ieee80211_regdomain rtw_regdom_rd = { } }; -static int rtw_ieee80211_channel_to_frequency(int chan, int band) -{ - /* NL80211_BAND_2GHZ */ - if (chan == 14) - return 2484; - else if (chan < 14) - return 2407 + chan * 5; - else - return 0; /* not supported */ -} - static void _rtw_reg_apply_flags(struct wiphy *wiphy) { struct adapter *padapter = wiphy_to_adapter(wiphy); @@ -82,10 +71,7 @@ static void _rtw_reg_apply_flags(struct wiphy *wiphy) /* channels apply by channel plans. */ for (i = 0; i < max_chan_nums; i++) { channel = channel_set[i].ChannelNum; - freq = - rtw_ieee80211_channel_to_frequency(channel, - NL80211_BAND_2GHZ); - + freq = rtw_ieee80211_channel_to_frequency(channel); ch = ieee80211_get_channel(wiphy, freq); if (ch) { if (channel_set[i].ScanType == SCAN_PASSIVE) diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index 1d929aca399c1..3659af7e519db 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -126,8 +126,8 @@ static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor) if (fbcursor->set & FB_CUR_SETPOS) sm750_hw_cursor_set_pos(cursor, - fbcursor->image.dx - info->var.xoffset, - fbcursor->image.dy - info->var.yoffset); + fbcursor->image.dx - info->var.xoffset, + fbcursor->image.dy - info->var.yoffset); if (fbcursor->set & FB_CUR_SETCMAP) { /* get the 16bit color of kernel means */ @@ -160,7 +160,7 @@ static void lynxfb_ops_fillrect(struct fb_info *info, { struct lynxfb_par *par; struct sm750_dev *sm750_dev; - unsigned int base, pitch, Bpp, rop; + unsigned int base, pitch, bpp, rop; u32 color; if (info->state != FBINFO_STATE_RUNNING) @@ -175,9 +175,9 @@ static void lynxfb_ops_fillrect(struct fb_info *info, */ base = par->crtc.o_screen; pitch = info->fix.line_length; - Bpp = info->var.bits_per_pixel >> 3; + bpp = info->var.bits_per_pixel >> 3; - color = (Bpp == 1) ? region->color : + color = (bpp == 1) ? region->color : ((u32 *)info->pseudo_palette)[region->color]; rop = (region->rop != ROP_COPY) ? HW_ROP2_XOR : HW_ROP2_COPY; @@ -190,7 +190,7 @@ static void lynxfb_ops_fillrect(struct fb_info *info, spin_lock(&sm750_dev->slock); sm750_dev->accel.de_fillrect(&sm750_dev->accel, - base, pitch, Bpp, + base, pitch, bpp, region->dx, region->dy, region->width, region->height, color, rop); @@ -202,7 +202,7 @@ static void lynxfb_ops_copyarea(struct fb_info *info, { struct lynxfb_par *par; struct sm750_dev *sm750_dev; - unsigned int base, pitch, Bpp; + unsigned int base, pitch, bpp; par = info->par; sm750_dev = par->dev; @@ -213,7 +213,7 @@ static void lynxfb_ops_copyarea(struct fb_info *info, */ base = par->crtc.o_screen; pitch = info->fix.line_length; - Bpp = info->var.bits_per_pixel >> 3; + bpp = info->var.bits_per_pixel >> 3; /* * If not use spin_lock, system will die if user load driver @@ -225,7 +225,7 @@ static void lynxfb_ops_copyarea(struct fb_info *info, sm750_dev->accel.de_copyarea(&sm750_dev->accel, base, pitch, region->sx, region->sy, - base, pitch, Bpp, region->dx, region->dy, + base, pitch, bpp, region->dx, region->dy, region->width, region->height, HW_ROP2_COPY); spin_unlock(&sm750_dev->slock); @@ -234,7 +234,7 @@ static void lynxfb_ops_copyarea(struct fb_info *info, static void lynxfb_ops_imageblit(struct fb_info *info, const struct fb_image *image) { - unsigned int base, pitch, Bpp; + unsigned int base, pitch, bpp; unsigned int fgcol, bgcol; struct lynxfb_par *par; struct sm750_dev *sm750_dev; @@ -247,7 +247,7 @@ static void lynxfb_ops_imageblit(struct fb_info *info, */ base = par->crtc.o_screen; pitch = info->fix.line_length; - Bpp = info->var.bits_per_pixel >> 3; + bpp = info->var.bits_per_pixel >> 3; /* TODO: Implement hardware acceleration for image->depth > 1 */ if (image->depth != 1) { @@ -274,7 +274,7 @@ static void lynxfb_ops_imageblit(struct fb_info *info, sm750_dev->accel.de_imageblit(&sm750_dev->accel, image->data, image->width >> 3, 0, - base, pitch, Bpp, + base, pitch, bpp, image->dx, image->dy, image->width, image->height, fgcol, bgcol, HW_ROP2_COPY); @@ -571,13 +571,19 @@ exit: static int lynxfb_ops_blank(int blank, struct fb_info *info) { + struct sm750_dev *sm750_dev; struct lynxfb_par *par; struct lynxfb_output *output; pr_debug("blank = %d.\n", blank); par = info->par; output = &par->output; - return output->proc_setBLANK(output, blank); + sm750_dev = par->dev; + + if (sm750_dev->revid == SM750LE_REVISION_ID) + return hw_sm750le_set_blank(output, blank); + else + return hw_sm750_set_blank(output, blank); } static int sm750fb_set_drv(struct lynxfb_par *par) @@ -598,15 +604,13 @@ static int sm750fb_set_drv(struct lynxfb_par *par) crtc->vidmem_size >>= 1; /* setup crtc and output member */ - sm750_dev->hwCursor = g_hwcursor; + sm750_dev->hw_cursor = g_hwcursor; crtc->line_pad = 16; crtc->xpanstep = 8; crtc->ypanstep = 1; crtc->ywrapstep = 0; - output->proc_setBLANK = (sm750_dev->revid == SM750LE_REVISION_ID) ? - hw_sm750le_set_blank : hw_sm750_set_blank; /* chip specific phase */ sm750_dev->accel.de_wait = (sm750_dev->revid == SM750LE_REVISION_ID) ? hw_sm750le_de_wait : hw_sm750_de_wait; diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h index 9cf8b3d30aacf..d7f40efe3a2ce 100644 --- a/drivers/staging/sm750fb/sm750.h +++ b/drivers/staging/sm750fb/sm750.h @@ -113,7 +113,7 @@ struct sm750_dev { * 2: secondary crtc hw cursor enabled * 3: both ctrc hw cursor enabled */ - int hwCursor; + int hw_cursor; }; struct lynx_cursor { @@ -169,8 +169,6 @@ struct lynxfb_output { * output->channel ==> &crtc->channel */ void *priv; - - int (*proc_setBLANK)(struct lynxfb_output *output, int blank); }; struct lynxfb_par { diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 5dbf8d53db09f..721b15b7e13b9 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -97,6 +97,13 @@ struct vchiq_arm_state { * tracked separately with the state. */ int peer_use_count; + + /* + * Flag to indicate that the first vchiq connect has made it through. + * This means that both sides should be fully ready, and we should + * be able to suspend after this point. + */ + int first_connect; }; static int @@ -273,6 +280,29 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state return 0; } +int +vchiq_platform_init_state(struct vchiq_state *state) +{ + struct vchiq_arm_state *platform_state; + + platform_state = devm_kzalloc(state->dev, sizeof(*platform_state), GFP_KERNEL); + if (!platform_state) + return -ENOMEM; + + rwlock_init(&platform_state->susp_res_lock); + + init_completion(&platform_state->ka_evt); + atomic_set(&platform_state->ka_use_count, 0); + atomic_set(&platform_state->ka_use_ack_count, 0); + atomic_set(&platform_state->ka_release_count, 0); + + platform_state->state = state; + + state->platform_state = (struct opaque_platform_state *)platform_state; + + return 0; +} + static struct vchiq_arm_state *vchiq_platform_get_arm_state(struct vchiq_state *state) { return (struct vchiq_arm_state *)state->platform_state; @@ -363,8 +393,7 @@ int vchiq_shutdown(struct vchiq_instance *instance) struct vchiq_state *state = instance->state; int ret = 0; - if (mutex_lock_killable(&state->mutex)) - return -EAGAIN; + mutex_lock(&state->mutex); /* Remove all services */ vchiq_shutdown_internal(state, instance); @@ -982,39 +1011,6 @@ exit: } int -vchiq_platform_init_state(struct vchiq_state *state) -{ - struct vchiq_arm_state *platform_state; - char threadname[16]; - - platform_state = devm_kzalloc(state->dev, sizeof(*platform_state), GFP_KERNEL); - if (!platform_state) - return -ENOMEM; - - snprintf(threadname, sizeof(threadname), "vchiq-keep/%d", - state->id); - platform_state->ka_thread = kthread_create(&vchiq_keepalive_thread_func, - (void *)state, threadname); - if (IS_ERR(platform_state->ka_thread)) { - dev_err(state->dev, "couldn't create thread %s\n", threadname); - return PTR_ERR(platform_state->ka_thread); - } - - rwlock_init(&platform_state->susp_res_lock); - - init_completion(&platform_state->ka_evt); - atomic_set(&platform_state->ka_use_count, 0); - atomic_set(&platform_state->ka_use_ack_count, 0); - atomic_set(&platform_state->ka_release_count, 0); - - platform_state->state = state; - - state->platform_state = (struct opaque_platform_state *)platform_state; - - return 0; -} - -int vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service, enum USE_TYPE_E use_type) { @@ -1329,19 +1325,37 @@ out: return ret; } -void vchiq_platform_connected(struct vchiq_state *state) -{ - struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); - - wake_up_process(arm_state->ka_thread); -} - void vchiq_platform_conn_state_changed(struct vchiq_state *state, enum vchiq_connstate oldstate, enum vchiq_connstate newstate) { + struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); + char threadname[16]; + dev_dbg(state->dev, "suspend: %d: %s->%s\n", state->id, get_conn_state_name(oldstate), get_conn_state_name(newstate)); + if (state->conn_state != VCHIQ_CONNSTATE_CONNECTED) + return; + + write_lock_bh(&arm_state->susp_res_lock); + if (arm_state->first_connect) { + write_unlock_bh(&arm_state->susp_res_lock); + return; + } + + arm_state->first_connect = 1; + write_unlock_bh(&arm_state->susp_res_lock); + snprintf(threadname, sizeof(threadname), "vchiq-keep/%d", + state->id); + arm_state->ka_thread = kthread_create(&vchiq_keepalive_thread_func, + (void *)state, + threadname); + if (IS_ERR(arm_state->ka_thread)) { + dev_err(state->dev, "suspend: Couldn't create thread %s\n", + threadname); + } else { + wake_up_process(arm_state->ka_thread); + } } static const struct of_device_id vchiq_of_match[] = { diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index e7b0c800a205d..e2cac0898b8fa 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -3343,7 +3343,6 @@ vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instanc return -EAGAIN; vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED); - vchiq_platform_connected(state); complete(&state->connect); } diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index 3b5c0618e5672..9b4e766990a49 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -575,8 +575,6 @@ int vchiq_send_remote_use(struct vchiq_state *state); int vchiq_send_remote_use_active(struct vchiq_state *state); -void vchiq_platform_connected(struct vchiq_state *state); - void vchiq_platform_conn_state_changed(struct vchiq_state *state, enum vchiq_connstate oldstate, enum vchiq_connstate newstate); diff --git a/drivers/staging/vme_user/vme.c b/drivers/staging/vme_user/vme.c index 42304c9f83a2d..2095de72596a7 100644 --- a/drivers/staging/vme_user/vme.c +++ b/drivers/staging/vme_user/vme.c @@ -809,7 +809,7 @@ EXPORT_SYMBOL(vme_master_free); * @vdev: Pointer to VME device struct vme_dev assigned to driver instance. * @route: Required src/destination combination. * - * Request a VME DMA controller with capability to perform transfers bewteen + * Request a VME DMA controller with capability to perform transfers between * requested source/destination combination. * * Return: Pointer to VME DMA resource on success, NULL on failure. @@ -1045,7 +1045,7 @@ void vme_dma_free_attribute(struct vme_dma_attr *attributes) EXPORT_SYMBOL(vme_dma_free_attribute); /** - * vme_dma_list_add - Add enty to a VME DMA list. + * vme_dma_list_add - Add entry to a VME DMA list. * @list: Pointer to VME list. * @src: Pointer to DMA list attribute to use as source. * @dest: Pointer to DMA list attribute to use as destination. @@ -1925,7 +1925,7 @@ EXPORT_SYMBOL(vme_unregister_driver); static int vme_bus_match(struct device *dev, const struct device_driver *drv) { - struct vme_driver *vme_drv; + const struct vme_driver *vme_drv; vme_drv = container_of(drv, struct vme_driver, driver); diff --git a/drivers/staging/vme_user/vme_fake.c b/drivers/staging/vme_user/vme_fake.c index 4a59c9069605f..731fbba17dfd6 100644 --- a/drivers/staging/vme_user/vme_fake.c +++ b/drivers/staging/vme_user/vme_fake.c @@ -1061,7 +1061,7 @@ static int __init fake_init(void) if (geoid >= VME_MAX_SLOTS) { pr_err("VME geographical address must be between 0 and %d (exclusive), but got %d\n", - VME_MAX_SLOTS, geoid); + VME_MAX_SLOTS, geoid); return -EINVAL; } diff --git a/drivers/staging/vme_user/vme_tsi148.h b/drivers/staging/vme_user/vme_tsi148.h index db246cbc54c39..f73ac92320bbf 100644 --- a/drivers/staging/vme_user/vme_tsi148.h +++ b/drivers/staging/vme_user/vme_tsi148.h @@ -1347,7 +1347,7 @@ static const int TSI148_LCSR_INTC_MBC[4] = { TSI148_LCSR_INTC_MB0C, #define TSI148_GCSR_GCTRL_LRST BIT(15) /* Local Reset */ #define TSI148_GCSR_GCTRL_SFAILEN BIT(14) /* System Fail enable */ #define TSI148_GCSR_GCTRL_BDFAILS BIT(13) /* Board Fail Status */ -#define TSI148_GCSR_GCTRL_SCON BIT(12) /* System Copntroller */ +#define TSI148_GCSR_GCTRL_SCON BIT(12) /* System Controller */ #define TSI148_GCSR_GCTRL_MEN BIT(11) /* Module Enable (READY) */ #define TSI148_GCSR_GCTRL_LMI3S BIT(7) /* Loc Monitor 3 Int Status */ |