From 5b7c4cabbb65f5c469464da6c5f614cbd7f730f2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 21 Feb 2023 18:24:12 -0800 Subject: Merge tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next Pull networking updates from Jakub Kicinski: "Core: - Add dedicated kmem_cache for typical/small skb->head, avoid having to access struct page at kfree time, and improve memory use. - Introduce sysctl to set default RPS configuration for new netdevs. - Define Netlink protocol specification format which can be used to describe messages used by each family and auto-generate parsers. Add tools for generating kernel data structures and uAPI headers. - Expose all net/core sysctls inside netns. - Remove 4s sleep in netpoll if carrier is instantly detected on boot. - Add configurable limit of MDB entries per port, and port-vlan. - Continue populating drop reasons throughout the stack. - Retire a handful of legacy Qdiscs and classifiers. Protocols: - Support IPv4 big TCP (TSO frames larger than 64kB). - Add IP_LOCAL_PORT_RANGE socket option, to control local port range on socket by socket basis. - Track and report in procfs number of MPTCP sockets used. - Support mixing IPv4 and IPv6 flows in the in-kernel MPTCP path manager. - IPv6: don't check net.ipv6.route.max_size and rely on garbage collection to free memory (similarly to IPv4). - Support Penultimate Segment Pop (PSP) flavor in SRv6 (RFC8986). - ICMP: add per-rate limit counters. - Add support for user scanning requests in ieee802154. - Remove static WEP support. - Support minimal Wi-Fi 7 Extremely High Throughput (EHT) rate reporting. - WiFi 7 EHT channel puncturing support (client & AP). BPF: - Add a rbtree data structure following the "next-gen data structure" precedent set by recently added linked list, that is, by using kfunc + kptr instead of adding a new BPF map type. - Expose XDP hints via kfuncs with initial support for RX hash and timestamp metadata. - Add BPF_F_NO_TUNNEL_KEY extension to bpf_skb_set_tunnel_key to better support decap on GRE tunnel devices not operating in collect metadata. - Improve x86 JIT's codegen for PROBE_MEM runtime error checks. - Remove the need for trace_printk_lock for bpf_trace_printk and bpf_trace_vprintk helpers. - Extend libbpf's bpf_tracing.h support for tracing arguments of kprobes/uprobes and syscall as a special case. - Significantly reduce the search time for module symbols by livepatch and BPF. - Enable cpumasks to be used as kptrs, which is useful for tracing programs tracking which tasks end up running on which CPUs in different time intervals. - Add support for BPF trampoline on s390x and riscv64. - Add capability to export the XDP features supported by the NIC. - Add __bpf_kfunc tag for marking kernel functions as kfuncs. - Add cgroup.memory=nobpf kernel parameter option to disable BPF memory accounting for container environments. Netfilter: - Remove the CLUSTERIP target. It has been marked as obsolete for years, and we still have WARN splats wrt races of the out-of-band /proc interface installed by this target. - Add 'destroy' commands to nf_tables. They are identical to the existing 'delete' commands, but do not return an error if the referenced object (set, chain, rule...) did not exist. Driver API: - Improve cpumask_local_spread() locality to help NICs set the right IRQ affinity on AMD platforms. - Separate C22 and C45 MDIO bus transactions more clearly. - Introduce new DCB table to control DSCP rewrite on egress. - Support configuration of Physical Layer Collision Avoidance (PLCA) Reconciliation Sublayer (RS) (802.3cg-2019). Modern version of shared medium Ethernet. - Support for MAC Merge layer (IEEE 802.3-2018 clause 99). Allowing preemption of low priority frames by high priority frames. - Add support for controlling MACSec offload using netlink SET. - Rework devlink instance refcounts to allow registration and de-registration under the instance lock. Split the code into multiple files, drop some of the unnecessarily granular locks and factor out common parts of netlink operation handling. - Add TX frame aggregation parameters (for USB drivers). - Add a new attr TCA_EXT_WARN_MSG to report TC (offload) warning messages with notifications for debug. - Allow offloading of UDP NEW connections via act_ct. - Add support for per action HW stats in TC. - Support hardware miss to TC action (continue processing in SW from a specific point in the action chain). - Warn if old Wireless Extension user space interface is used with modern cfg80211/mac80211 drivers. Do not support Wireless Extensions for Wi-Fi 7 devices at all. Everyone should switch to using nl80211 interface instead. - Improve the CAN bit timing configuration. Use extack to return error messages directly to user space, update the SJW handling, including the definition of a new default value that will benefit CAN-FD controllers, by increasing their oscillator tolerance. New hardware / drivers: - Ethernet: - nVidia BlueField-3 support (control traffic driver) - Ethernet support for imx93 SoCs - Motorcomm yt8531 gigabit Ethernet PHY - onsemi NCN26000 10BASE-T1S PHY (with support for PLCA) - Microchip LAN8841 PHY (incl. cable diagnostics and PTP) - Amlogic gxl MDIO mux - WiFi: - RealTek RTL8188EU (rtl8xxxu) - Qualcomm Wi-Fi 7 devices (ath12k) - CAN: - Renesas R-Car V4H Drivers: - Bluetooth: - Set Per Platform Antenna Gain (PPAG) for Intel controllers. - Ethernet NICs: - Intel (1G, igc): - support TSN / Qbv / packet scheduling features of i226 model - Intel (100G, ice): - use GNSS subsystem instead of TTY - multi-buffer XDP support - extend support for GPIO pins to E823 devices - nVidia/Mellanox: - update the shared buffer configuration on PFC commands - implement PTP adjphase function for HW offset control - TC support for Geneve and GRE with VF tunnel offload - more efficient crypto key management method - multi-port eswitch support - Netronome/Corigine: - add DCB IEEE support - support IPsec offloading for NFP3800 - Freescale/NXP (enetc): - support XDP_REDIRECT for XDP non-linear buffers - improve reconfig, avoid link flap and waiting for idle - support MAC Merge layer - Other NICs: - sfc/ef100: add basic devlink support for ef100 - ionic: rx_push mode operation (writing descriptors via MMIO) - bnxt: use the auxiliary bus abstraction for RDMA - r8169: disable ASPM and reset bus in case of tx timeout - cpsw: support QSGMII mode for J721e CPSW9G - cpts: support pulse-per-second output - ngbe: add an mdio bus driver - usbnet: optimize usbnet_bh() by avoiding unnecessary queuing - r8152: handle devices with FW with NCM support - amd-xgbe: support 10Mbps, 2.5GbE speeds and rx-adaptation - virtio-net: support multi buffer XDP - virtio/vsock: replace virtio_vsock_pkt with sk_buff - tsnep: XDP support - Ethernet high-speed switches: - nVidia/Mellanox (mlxsw): - add support for latency TLV (in FW control messages) - Microchip (sparx5): - separate explicit and implicit traffic forwarding rules, make the implicit rules always active - add support for egress DSCP rewrite - IS0 VCAP support (Ingress Classification) - IS2 VCAP filters (protos, L3 addrs, L4 ports, flags, ToS etc.) - ES2 VCAP support (Egress Access Control) - support for Per-Stream Filtering and Policing (802.1Q, 8.6.5.1) - Ethernet embedded switches: - Marvell (mv88e6xxx): - add MAB (port auth) offload support - enable PTP receive for mv88e6390 - NXP (ocelot): - support MAC Merge layer - support for the the vsc7512 internal copper phys - Microchip: - lan9303: convert to PHYLINK - lan966x: support TC flower filter statistics - lan937x: PTP support for KSZ9563/KSZ8563 and LAN937x - lan937x: support Credit Based Shaper configuration - ksz9477: support Energy Efficient Ethernet - other: - qca8k: convert to regmap read/write API, use bulk operations - rswitch: Improve TX timestamp accuracy - Intel WiFi (iwlwifi): - EHT (Wi-Fi 7) rate reporting - STEP equalizer support: transfer some STEP (connection to radio on platforms with integrated wifi) related parameters from the BIOS to the firmware. - Qualcomm 802.11ax WiFi (ath11k): - IPQ5018 support - Fine Timing Measurement (FTM) responder role support - channel 177 support - MediaTek WiFi (mt76): - per-PHY LED support - mt7996: EHT (Wi-Fi 7) support - Wireless Ethernet Dispatch (WED) reset support - switch to using page pool allocator - RealTek WiFi (rtw89): - support new version of Bluetooth co-existance - Mobile: - rmnet: support TX aggregation" * tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1872 commits) page_pool: add a comment explaining the fragment counter usage net: ethtool: fix __ethtool_dev_mm_supported() implementation ethtool: pse-pd: Fix double word in comments xsk: add linux/vmalloc.h to xsk.c sefltests: netdevsim: wait for devlink instance after netns removal selftest: fib_tests: Always cleanup before exit net/mlx5e: Align IPsec ASO result memory to be as required by hardware net/mlx5e: TC, Set CT miss to the specific ct action instance net/mlx5e: Rename CHAIN_TO_REG to MAPPED_OBJ_TO_REG net/mlx5: Refactor tc miss handling to a single function net/mlx5: Kconfig: Make tc offload depend on tc skb extension net/sched: flower: Support hardware miss to tc action net/sched: flower: Move filter handle initialization earlier net/sched: cls_api: Support hardware miss to tc action net/sched: Rename user cookie and act cookie sfc: fix builds without CONFIG_RTC_LIB sfc: clean up some inconsistent indentings net/mlx4_en: Introduce flexible array to silence overflow warning net: lan966x: Fix possible deadlock inside PTP net/ulp: Remove redundant ->clone() test in inet_clone_ulp(). ... --- drivers/media/pci/zoran/zoran_device.c | 956 +++++++++++++++++++++++++++++++++ 1 file changed, 956 insertions(+) create mode 100644 drivers/media/pci/zoran/zoran_device.c (limited to 'drivers/media/pci/zoran/zoran_device.c') diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c new file mode 100644 index 000000000..31f049b55 --- /dev/null +++ b/drivers/media/pci/zoran/zoran_device.c @@ -0,0 +1,956 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Zoran zr36057/zr36067 PCI controller driver, for the + * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux + * Media Labs LML33/LML33R10. + * + * This part handles device access (PCI/I2C/codec/...) + * + * Copyright (C) 2000 Serguei Miridonov + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "videocodec.h" +#include "zoran.h" +#include "zoran_device.h" +#include "zoran_card.h" + +#define IRQ_MASK (ZR36057_ISR_GIRQ0 | \ + ZR36057_ISR_GIRQ1 | \ + ZR36057_ISR_JPEG_REP_IRQ) + +static bool lml33dpath; /* default = 0 + * 1 will use digital path in capture + * mode instead of analog. It can be + * used for picture adjustments using + * tool like xawtv while watching image + * on TV monitor connected to the output. + * However, due to absence of 75 Ohm + * load on Bt819 input, there will be + * some image imperfections + */ + +module_param(lml33dpath, bool, 0644); +MODULE_PARM_DESC(lml33dpath, "Use digital path capture mode (on LML33 cards)"); + +/* + * initialize video front end + */ +static void zr36057_init_vfe(struct zoran *zr) +{ + u32 reg; + + reg = btread(ZR36057_VFESPFR); + reg |= ZR36057_VFESPFR_LITTLE_ENDIAN; + reg &= ~ZR36057_VFESPFR_VCLK_POL; + reg |= ZR36057_VFESPFR_EXT_FL; + reg |= ZR36057_VFESPFR_TOP_FIELD; + btwrite(reg, ZR36057_VFESPFR); + reg = btread(ZR36057_VDCR); + if (pci_pci_problems & PCIPCI_TRITON) + // || zr->revision < 1) // Revision 1 has also Triton support + reg &= ~ZR36057_VDCR_TRITON; + else + reg |= ZR36057_VDCR_TRITON; + btwrite(reg, ZR36057_VDCR); +} + +/* + * General Purpose I/O and Guest bus access + */ + +/* + * This is a bit tricky. When a board lacks a GPIO function, the corresponding + * GPIO bit number in the card_info structure is set to 0. + */ + +void GPIO(struct zoran *zr, int bit, unsigned int value) +{ + u32 reg; + u32 mask; + + /* Make sure the bit number is legal + * A bit number of -1 (lacking) gives a mask of 0, + * making it harmless + */ + mask = (1 << (24 + bit)) & 0xff000000; + reg = btread(ZR36057_GPPGCR1) & ~mask; + if (value) + reg |= mask; + + btwrite(reg, ZR36057_GPPGCR1); + udelay(1); +} + +/* + * Wait til post office is no longer busy + */ + +int post_office_wait(struct zoran *zr) +{ + u32 por; + + while ((por = btread(ZR36057_POR)) & ZR36057_POR_PO_PEN) { + /* wait for something to happen */ + /* TODO add timeout */ + } + if ((por & ZR36057_POR_PO_TIME) && !zr->card.gws_not_connected) { + /* In LML33/BUZ \GWS line is not connected, so it has always timeout set */ + pci_info(zr->pci_dev, "pop timeout %08x\n", por); + return -1; + } + + return 0; +} + +int post_office_write(struct zoran *zr, unsigned int guest, + unsigned int reg, unsigned int value) +{ + u32 por; + + por = + ZR36057_POR_PO_DIR | ZR36057_POR_PO_TIME | ((guest & 7) << 20) | + ((reg & 7) << 16) | (value & 0xFF); + btwrite(por, ZR36057_POR); + + return post_office_wait(zr); +} + +int post_office_read(struct zoran *zr, unsigned int guest, unsigned int reg) +{ + u32 por; + + por = ZR36057_POR_PO_TIME | ((guest & 7) << 20) | ((reg & 7) << 16); + btwrite(por, ZR36057_POR); + if (post_office_wait(zr) < 0) + return -1; + + return btread(ZR36057_POR) & 0xFF; +} + +/* + * JPEG Codec access + */ + +void jpeg_codec_sleep(struct zoran *zr, int sleep) +{ + GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_SLEEP], !sleep); + if (!sleep) { + pci_dbg(zr->pci_dev, "%s() - wake GPIO=0x%08x\n", + __func__, btread(ZR36057_GPPGCR1)); + usleep_range(500, 1000); + } else { + pci_dbg(zr->pci_dev, "%s() - sleep GPIO=0x%08x\n", + __func__, btread(ZR36057_GPPGCR1)); + udelay(2); + } +} + +int jpeg_codec_reset(struct zoran *zr) +{ + /* Take the codec out of sleep */ + jpeg_codec_sleep(zr, 0); + + if (zr->card.gpcs[GPCS_JPEG_RESET] != 0xff) { + post_office_write(zr, zr->card.gpcs[GPCS_JPEG_RESET], 0, + 0); + udelay(2); + } else { + GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 0); + udelay(2); + GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 1); + udelay(2); + } + + return 0; +} + +/* + * Set the registers for the size we have specified. Don't bother + * trying to understand this without the ZR36057 manual in front of + * you [AC]. + */ +static void zr36057_adjust_vfe(struct zoran *zr, enum zoran_codec_mode mode) +{ + u32 reg; + + switch (mode) { + case BUZ_MODE_MOTION_DECOMPRESS: + btand(~ZR36057_VFESPFR_EXT_FL, ZR36057_VFESPFR); + reg = btread(ZR36057_VFEHCR); + if ((reg & (1 << 10)) && zr->card.type != LML33R10) + reg += ((1 << 10) | 1); + + btwrite(reg, ZR36057_VFEHCR); + break; + case BUZ_MODE_MOTION_COMPRESS: + case BUZ_MODE_IDLE: + default: + if ((zr->norm & V4L2_STD_NTSC) || + (zr->card.type == LML33R10 && + (zr->norm & V4L2_STD_PAL))) + btand(~ZR36057_VFESPFR_EXT_FL, ZR36057_VFESPFR); + else + btor(ZR36057_VFESPFR_EXT_FL, ZR36057_VFESPFR); + reg = btread(ZR36057_VFEHCR); + if (!(reg & (1 << 10)) && zr->card.type != LML33R10) + reg -= ((1 << 10) | 1); + + btwrite(reg, ZR36057_VFEHCR); + break; + } +} + +/* + * set geometry + */ + +static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height, + const struct zoran_format *format) +{ + const struct tvnorm *tvn; + unsigned int h_start, h_end, v_start, v_end; + unsigned int disp_mode; + unsigned int vid_win_wid, vid_win_ht; + unsigned int hcrop1, hcrop2, vcrop1, vcrop2; + unsigned int wa, we, ha, he; + unsigned int X, Y, hor_dcm, ver_dcm; + u32 reg; + + tvn = zr->timing; + + wa = tvn->wa; + ha = tvn->ha; + + pci_dbg(zr->pci_dev, "set_vfe() - width = %d, height = %d\n", video_width, video_height); + + if (video_width < BUZ_MIN_WIDTH || + video_height < BUZ_MIN_HEIGHT || + video_width > wa || video_height > ha) { + pci_err(zr->pci_dev, "set_vfe: w=%d h=%d not valid\n", video_width, video_height); + return; + } + + /**** zr36057 ****/ + + /* horizontal */ + vid_win_wid = video_width; + X = DIV_ROUND_UP(vid_win_wid * 64, tvn->wa); + we = (vid_win_wid * 64) / X; + hor_dcm = 64 - X; + hcrop1 = 2 * ((tvn->wa - we) / 4); + hcrop2 = tvn->wa - we - hcrop1; + h_start = tvn->h_start ? tvn->h_start : 1; + /* (Ronald) Original comment: + * "| 1 Doesn't have any effect, tested on both a DC10 and a DC10+" + * this is false. It inverses chroma values on the LML33R10 (so Cr + * suddenly is shown as Cb and reverse, really cool effect if you + * want to see blue faces, not useful otherwise). So don't use |1. + * However, the DC10 has '0' as h_start, but does need |1, so we + * use a dirty check... + */ + h_end = h_start + tvn->wa - 1; + h_start += hcrop1; + h_end -= hcrop2; + reg = ((h_start & ZR36057_VFEHCR_HMASK) << ZR36057_VFEHCR_H_START) + | ((h_end & ZR36057_VFEHCR_HMASK) << ZR36057_VFEHCR_H_END); + if (zr->card.vfe_pol.hsync_pol) + reg |= ZR36057_VFEHCR_HS_POL; + btwrite(reg, ZR36057_VFEHCR); + + /* Vertical */ + disp_mode = !(video_height > BUZ_MAX_HEIGHT / 2); + vid_win_ht = disp_mode ? video_height : video_height / 2; + Y = DIV_ROUND_UP(vid_win_ht * 64 * 2, tvn->ha); + he = (vid_win_ht * 64) / Y; + ver_dcm = 64 - Y; + vcrop1 = (tvn->ha / 2 - he) / 2; + vcrop2 = tvn->ha / 2 - he - vcrop1; + v_start = tvn->v_start; + // FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP + v_end = v_start + tvn->ha / 2; // - 1; + v_start += vcrop1; + v_end -= vcrop2; + reg = ((v_start & ZR36057_VFEVCR_VMASK) << ZR36057_VFEVCR_V_START) + | ((v_end & ZR36057_VFEVCR_VMASK) << ZR36057_VFEVCR_V_END); + if (zr->card.vfe_pol.vsync_pol) + reg |= ZR36057_VFEVCR_VS_POL; + btwrite(reg, ZR36057_VFEVCR); + + /* scaler and pixel format */ + reg = 0; + reg |= (hor_dcm << ZR36057_VFESPFR_HOR_DCM); + reg |= (ver_dcm << ZR36057_VFESPFR_VER_DCM); + reg |= (disp_mode << ZR36057_VFESPFR_DISP_MODE); + /* + * RJ: I don't know, why the following has to be the opposite + * of the corresponding ZR36060 setting, but only this way + * we get the correct colors when uncompressing to the screen + */ + //reg |= ZR36057_VFESPFR_VCLK_POL; + /* RJ: Don't know if that is needed for NTSC also */ + if (!(zr->norm & V4L2_STD_NTSC)) + reg |= ZR36057_VFESPFR_EXT_FL; // NEEDED!!!!!!! Wolfgang + reg |= ZR36057_VFESPFR_TOP_FIELD; + if (hor_dcm >= 48) + reg |= 3 << ZR36057_VFESPFR_H_FILTER; /* 5 tap filter */ + else if (hor_dcm >= 32) + reg |= 2 << ZR36057_VFESPFR_H_FILTER; /* 4 tap filter */ + else if (hor_dcm >= 16) + reg |= 1 << ZR36057_VFESPFR_H_FILTER; /* 3 tap filter */ + + reg |= format->vfespfr; + btwrite(reg, ZR36057_VFESPFR); + + /* display configuration */ + reg = (16 << ZR36057_VDCR_MIN_PIX) + | (vid_win_ht << ZR36057_VDCR_VID_WIN_HT) + | (vid_win_wid << ZR36057_VDCR_VID_WIN_WID); + if (pci_pci_problems & PCIPCI_TRITON) + // || zr->revision < 1) // Revision 1 has also Triton support + reg &= ~ZR36057_VDCR_TRITON; + else + reg |= ZR36057_VDCR_TRITON; + btwrite(reg, ZR36057_VDCR); + + zr36057_adjust_vfe(zr, zr->codec_mode); +} + +/* Enable/Disable uncompressed memory grabbing of the 36057 */ +void zr36057_set_memgrab(struct zoran *zr, int mode) +{ + if (mode) { + /* We only check SnapShot and not FrameGrab here. SnapShot==1 + * means a capture is already in progress, but FrameGrab==1 + * doesn't necessary mean that. It's more correct to say a 1 + * to 0 transition indicates a capture completed. If a + * capture is pending when capturing is tuned off, FrameGrab + * will be stuck at 1 until capturing is turned back on. + */ + if (btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SNAP_SHOT) + pci_warn(zr->pci_dev, "%s(1) with SnapShot on!?\n", __func__); + + /* switch on VSync interrupts */ + btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts + btor(zr->card.vsync_int, ZR36057_ICR); // SW + + /* enable SnapShot */ + btor(ZR36057_VSSFGR_SNAP_SHOT, ZR36057_VSSFGR); + + /* Set zr36057 video front end and enable video */ + zr36057_set_vfe(zr, zr->v4l_settings.width, + zr->v4l_settings.height, + zr->v4l_settings.format); + } else { + /* switch off VSync interrupts */ + btand(~zr->card.vsync_int, ZR36057_ICR); // SW + + /* re-enable grabbing to screen if it was running */ + btand(~ZR36057_VDCR_VID_EN, ZR36057_VDCR); + btand(~ZR36057_VSSFGR_SNAP_SHOT, ZR36057_VSSFGR); + } +} + +/***************************************************************************** + * * + * Set up the Buz-specific MJPEG part * + * * + *****************************************************************************/ + +static inline void set_frame(struct zoran *zr, int val) +{ + GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_FRAME], val); +} + +static void set_videobus_dir(struct zoran *zr, int val) +{ + switch (zr->card.type) { + case LML33: + case LML33R10: + if (!lml33dpath) + GPIO(zr, 5, val); + else + GPIO(zr, 5, 1); + break; + default: + GPIO(zr, zr->card.gpio[ZR_GPIO_VID_DIR], + zr->card.gpio_pol[ZR_GPIO_VID_DIR] ? !val : val); + break; + } +} + +static void init_jpeg_queue(struct zoran *zr) +{ + int i; + + /* re-initialize DMA ring stuff */ + zr->jpg_que_head = 0; + zr->jpg_dma_head = 0; + zr->jpg_dma_tail = 0; + zr->jpg_que_tail = 0; + zr->jpg_seq_num = 0; + zr->jpeg_error = 0; + zr->num_errors = 0; + zr->jpg_err_seq = 0; + zr->jpg_err_shift = 0; + zr->jpg_queued_num = 0; + for (i = 0; i < BUZ_NUM_STAT_COM; i++) + zr->stat_com[i] = cpu_to_le32(1); /* mark as unavailable to zr36057 */ +} + +static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + const struct tvnorm *tvn; + u32 reg; + + tvn = zr->timing; + + /* assert P_Reset, disable code transfer, deassert Active */ + btwrite(0, ZR36057_JPC); + + /* MJPEG compression mode */ + switch (mode) { + case BUZ_MODE_MOTION_COMPRESS: + default: + reg = ZR36057_JMC_MJPG_CMP_MODE; + break; + + case BUZ_MODE_MOTION_DECOMPRESS: + reg = ZR36057_JMC_MJPG_EXP_MODE; + reg |= ZR36057_JMC_SYNC_MSTR; + /* RJ: The following is experimental - improves the output to screen */ + //if(zr->jpg_settings.VFIFO_FB) reg |= ZR36057_JMC_VFIFO_FB; // No, it doesn't. SM + break; + + case BUZ_MODE_STILL_COMPRESS: + reg = ZR36057_JMC_JPG_CMP_MODE; + break; + + case BUZ_MODE_STILL_DECOMPRESS: + reg = ZR36057_JMC_JPG_EXP_MODE; + break; + } + reg |= ZR36057_JMC_JPG; + if (zr->jpg_settings.field_per_buff == 1) + reg |= ZR36057_JMC_FLD_PER_BUFF; + btwrite(reg, ZR36057_JMC); + + /* vertical */ + btor(ZR36057_VFEVCR_VS_POL, ZR36057_VFEVCR); + reg = (6 << ZR36057_VSP_VSYNC_SIZE) | + (tvn->ht << ZR36057_VSP_FRM_TOT); + btwrite(reg, ZR36057_VSP); + reg = ((zr->jpg_settings.img_y + tvn->v_start) << ZR36057_FVAP_NAY) | + (zr->jpg_settings.img_height << ZR36057_FVAP_PAY); + btwrite(reg, ZR36057_FVAP); + + /* horizontal */ + if (zr->card.vfe_pol.hsync_pol) + btor(ZR36057_VFEHCR_HS_POL, ZR36057_VFEHCR); + else + btand(~ZR36057_VFEHCR_HS_POL, ZR36057_VFEHCR); + reg = ((tvn->h_sync_start) << ZR36057_HSP_HSYNC_START) | + (tvn->wt << ZR36057_HSP_LINE_TOT); + btwrite(reg, ZR36057_HSP); + reg = ((zr->jpg_settings.img_x + + tvn->h_start + 4) << ZR36057_FHAP_NAX) | + (zr->jpg_settings.img_width << ZR36057_FHAP_PAX); + btwrite(reg, ZR36057_FHAP); + + /* field process parameters */ + if (zr->jpg_settings.odd_even) + reg = ZR36057_FPP_ODD_EVEN; + else + reg = 0; + + btwrite(reg, ZR36057_FPP); + + /* Set proper VCLK Polarity, else colors will be wrong during playback */ + //btor(ZR36057_VFESPFR_VCLK_POL, ZR36057_VFESPFR); + + /* code base address */ + btwrite(zr->p_sc, ZR36057_JCBA); + + /* FIFO threshold (FIFO is 160. double words) */ + /* NOTE: decimal values here */ + switch (mode) { + case BUZ_MODE_STILL_COMPRESS: + case BUZ_MODE_MOTION_COMPRESS: + if (zr->card.type != BUZ) + reg = 140; + else + reg = 60; + break; + + case BUZ_MODE_STILL_DECOMPRESS: + case BUZ_MODE_MOTION_DECOMPRESS: + reg = 20; + break; + + default: + reg = 80; + break; + } + btwrite(reg, ZR36057_JCFT); + zr36057_adjust_vfe(zr, mode); +} + +void clear_interrupt_counters(struct zoran *zr) +{ + zr->intr_counter_GIRQ1 = 0; + zr->intr_counter_GIRQ0 = 0; + zr->intr_counter_cod_rep_irq = 0; + zr->intr_counter_jpeg_rep_irq = 0; + zr->field_counter = 0; + zr->irq1_in = 0; + zr->irq1_out = 0; + zr->jpeg_in = 0; + zr->jpeg_out = 0; + zr->JPEG_0 = 0; + zr->JPEG_1 = 0; + zr->end_event_missed = 0; + zr->jpeg_missed = 0; + zr->jpeg_max_missed = 0; + zr->jpeg_min_missed = 0x7fffffff; +} + +static u32 count_reset_interrupt(struct zoran *zr) +{ + u32 isr; + + isr = btread(ZR36057_ISR) & 0x78000000; + if (isr) { + if (isr & ZR36057_ISR_GIRQ1) { + btwrite(ZR36057_ISR_GIRQ1, ZR36057_ISR); + zr->intr_counter_GIRQ1++; + } + if (isr & ZR36057_ISR_GIRQ0) { + btwrite(ZR36057_ISR_GIRQ0, ZR36057_ISR); + zr->intr_counter_GIRQ0++; + } + if (isr & ZR36057_ISR_COD_REP_IRQ) { + btwrite(ZR36057_ISR_COD_REP_IRQ, ZR36057_ISR); + zr->intr_counter_cod_rep_irq++; + } + if (isr & ZR36057_ISR_JPEG_REP_IRQ) { + btwrite(ZR36057_ISR_JPEG_REP_IRQ, ZR36057_ISR); + zr->intr_counter_jpeg_rep_irq++; + } + } + return isr; +} + +void jpeg_start(struct zoran *zr) +{ + int reg; + + zr->frame_num = 0; + + /* deassert P_reset, disable code transfer, deassert Active */ + btwrite(ZR36057_JPC_P_RESET, ZR36057_JPC); + /* stop flushing the internal code buffer */ + btand(~ZR36057_MCTCR_C_FLUSH, ZR36057_MCTCR); + /* enable code transfer */ + btor(ZR36057_JPC_COD_TRNS_EN, ZR36057_JPC); + + /* clear IRQs */ + btwrite(IRQ_MASK, ZR36057_ISR); + /* enable the JPEG IRQs */ + btwrite(zr->card.jpeg_int | ZR36057_ICR_JPEG_REP_IRQ | ZR36057_ICR_INT_PIN_EN, + ZR36057_ICR); + + set_frame(zr, 0); // \FRAME + + /* set the JPEG codec guest ID */ + reg = (zr->card.gpcs[1] << ZR36057_JCGI_JPE_GUEST_ID) | + (0 << ZR36057_JCGI_JPE_GUEST_REG); + btwrite(reg, ZR36057_JCGI); + + if (zr->card.video_vfe == CODEC_TYPE_ZR36016 && + zr->card.video_codec == CODEC_TYPE_ZR36050) { + /* Enable processing on the ZR36016 */ + if (zr->vfe) + zr36016_write(zr->vfe, 0, 1); + + /* load the address of the GO register in the ZR36050 latch */ + post_office_write(zr, 0, 0, 0); + } + + /* assert Active */ + btor(ZR36057_JPC_ACTIVE, ZR36057_JPC); + + /* enable the Go generation */ + btor(ZR36057_JMC_GO_EN, ZR36057_JMC); + usleep_range(30, 100); + + set_frame(zr, 1); // /FRAME +} + +void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct vfe_settings cap; + int field_size = zr->buffer_size / zr->jpg_settings.field_per_buff; + + zr->codec_mode = mode; + + cap.x = zr->jpg_settings.img_x; + cap.y = zr->jpg_settings.img_y; + cap.width = zr->jpg_settings.img_width; + cap.height = zr->jpg_settings.img_height; + cap.decimation = + zr->jpg_settings.hor_dcm | (zr->jpg_settings.ver_dcm << 8); + cap.quality = zr->jpg_settings.jpg_comp.quality; + + switch (mode) { + case BUZ_MODE_MOTION_COMPRESS: { + struct jpeg_app_marker app; + struct jpeg_com_marker com; + + /* In motion compress mode, the decoder output must be enabled, and + * the video bus direction set to input. + */ + set_videobus_dir(zr, 0); + decoder_call(zr, video, s_stream, 1); + encoder_call(zr, video, s_routing, 0, 0, 0); + + /* Take the JPEG codec and the VFE out of sleep */ + jpeg_codec_sleep(zr, 0); + + /* set JPEG app/com marker */ + app.appn = zr->jpg_settings.jpg_comp.APPn; + app.len = zr->jpg_settings.jpg_comp.APP_len; + memcpy(app.data, zr->jpg_settings.jpg_comp.APP_data, 60); + zr->codec->control(zr->codec, CODEC_S_JPEG_APP_DATA, + sizeof(struct jpeg_app_marker), &app); + + com.len = zr->jpg_settings.jpg_comp.COM_len; + memcpy(com.data, zr->jpg_settings.jpg_comp.COM_data, 60); + zr->codec->control(zr->codec, CODEC_S_JPEG_COM_DATA, + sizeof(struct jpeg_com_marker), &com); + + /* Setup the JPEG codec */ + zr->codec->control(zr->codec, CODEC_S_JPEG_TDS_BYTE, + sizeof(int), &field_size); + zr->codec->set_video(zr->codec, zr->timing, &cap, + &zr->card.vfe_pol); + zr->codec->set_mode(zr->codec, CODEC_DO_COMPRESSION); + + /* Setup the VFE */ + if (zr->vfe) { + zr->vfe->control(zr->vfe, CODEC_S_JPEG_TDS_BYTE, + sizeof(int), &field_size); + zr->vfe->set_video(zr->vfe, zr->timing, &cap, + &zr->card.vfe_pol); + zr->vfe->set_mode(zr->vfe, CODEC_DO_COMPRESSION); + } + + init_jpeg_queue(zr); + zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO + + clear_interrupt_counters(zr); + pci_dbg(zr->pci_dev, "enable_jpg(MOTION_COMPRESS)\n"); + break; + } + + case BUZ_MODE_MOTION_DECOMPRESS: + /* In motion decompression mode, the decoder output must be disabled, and + * the video bus direction set to output. + */ + decoder_call(zr, video, s_stream, 0); + set_videobus_dir(zr, 1); + encoder_call(zr, video, s_routing, 1, 0, 0); + + /* Take the JPEG codec and the VFE out of sleep */ + jpeg_codec_sleep(zr, 0); + /* Setup the VFE */ + if (zr->vfe) { + zr->vfe->set_video(zr->vfe, zr->timing, &cap, + &zr->card.vfe_pol); + zr->vfe->set_mode(zr->vfe, CODEC_DO_EXPANSION); + } + /* Setup the JPEG codec */ + zr->codec->set_video(zr->codec, zr->timing, &cap, + &zr->card.vfe_pol); + zr->codec->set_mode(zr->codec, CODEC_DO_EXPANSION); + + init_jpeg_queue(zr); + zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO + + clear_interrupt_counters(zr); + pci_dbg(zr->pci_dev, "enable_jpg(MOTION_DECOMPRESS)\n"); + break; + + case BUZ_MODE_IDLE: + default: + /* shut down processing */ + btand(~(zr->card.jpeg_int | ZR36057_ICR_JPEG_REP_IRQ), + ZR36057_ICR); + btwrite(zr->card.jpeg_int | ZR36057_ICR_JPEG_REP_IRQ, + ZR36057_ISR); + btand(~ZR36057_JMC_GO_EN, ZR36057_JMC); // \Go_en + + msleep(50); + + set_videobus_dir(zr, 0); + set_frame(zr, 1); // /FRAME + btor(ZR36057_MCTCR_C_FLUSH, ZR36057_MCTCR); // /CFlush + btwrite(0, ZR36057_JPC); // \P_Reset,\CodTrnsEn,\Active + btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC); + btand(~ZR36057_JMC_SYNC_MSTR, ZR36057_JMC); + jpeg_codec_reset(zr); + jpeg_codec_sleep(zr, 1); + zr36057_adjust_vfe(zr, mode); + + decoder_call(zr, video, s_stream, 1); + encoder_call(zr, video, s_routing, 0, 0, 0); + + pci_dbg(zr->pci_dev, "enable_jpg(IDLE)\n"); + break; + } +} + +/* when this is called the spinlock must be held */ +void zoran_feed_stat_com(struct zoran *zr) +{ + /* move frames from pending queue to DMA */ + + int i, max_stat_com; + struct zr_buffer *buf; + struct vb2_v4l2_buffer *vbuf; + dma_addr_t phys_addr = 0; + unsigned long flags; + unsigned long payload; + + max_stat_com = + (zr->jpg_settings.tmp_dcm == + 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1); + + spin_lock_irqsave(&zr->queued_bufs_lock, flags); + while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com) { + buf = list_first_entry_or_null(&zr->queued_bufs, struct zr_buffer, queue); + if (!buf) { + pci_err(zr->pci_dev, "No buffer available to queue\n"); + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + return; + } + list_del(&buf->queue); + zr->buf_in_reserve--; + vbuf = &buf->vbuf; + vbuf->vb2_buf.state = VB2_BUF_STATE_ACTIVE; + phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); + payload = vb2_get_plane_payload(&vbuf->vb2_buf, 0); + if (payload == 0) + payload = zr->buffer_size; + if (zr->jpg_settings.tmp_dcm == 1) { + /* fill 1 stat_com entry */ + i = (zr->jpg_dma_head - + zr->jpg_err_shift) & BUZ_MASK_STAT_COM; + if (!(zr->stat_com[i] & cpu_to_le32(1))) + break; + zr->stat_comb[i * 2] = cpu_to_le32(phys_addr); + zr->stat_comb[i * 2 + 1] = cpu_to_le32((payload >> 1) | 1); + zr->inuse[i] = buf; + zr->stat_com[i] = cpu_to_le32(zr->p_scb + i * 2 * 4); + } else { + /* fill 2 stat_com entries */ + i = ((zr->jpg_dma_head - + zr->jpg_err_shift) & 1) * 2; + if (!(zr->stat_com[i] & cpu_to_le32(1))) + break; + zr->stat_com[i] = cpu_to_le32(zr->p_scb + i * 2 * 4); + zr->stat_com[i + 1] = cpu_to_le32(zr->p_scb + i * 2 * 4); + + zr->stat_comb[i * 2] = cpu_to_le32(phys_addr); + zr->stat_comb[i * 2 + 1] = cpu_to_le32((payload >> 1) | 1); + + zr->inuse[i] = buf; + zr->inuse[i + 1] = NULL; + } + zr->jpg_dma_head++; + } + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) + zr->jpg_queued_num++; +} + +/* when this is called the spinlock must be held */ +static void zoran_reap_stat_com(struct zoran *zr) +{ + /* move frames from DMA queue to done queue */ + + int i; + u32 stat_com; + unsigned int seq; + unsigned int dif; + unsigned long flags; + struct zr_buffer *buf; + unsigned int size = 0; + u32 fcnt; + + /* + * In motion decompress we don't have a hardware frame counter, + * we just count the interrupts here + */ + + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) + zr->jpg_seq_num++; + + spin_lock_irqsave(&zr->queued_bufs_lock, flags); + while (zr->jpg_dma_tail < zr->jpg_dma_head) { + if (zr->jpg_settings.tmp_dcm == 1) + i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; + else + i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2; + + stat_com = le32_to_cpu(zr->stat_com[i]); + if ((stat_com & 1) == 0) { + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + return; + } + + fcnt = (stat_com & GENMASK(31, 24)) >> 24; + size = (stat_com & GENMASK(22, 1)) >> 1; + + buf = zr->inuse[i]; + if (!buf) { + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + pci_err(zr->pci_dev, "No buffer at slot %d\n", i); + return; + } + buf->vbuf.vb2_buf.timestamp = ktime_get_ns(); + + if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { + vb2_set_plane_payload(&buf->vbuf.vb2_buf, 0, size); + + /* update sequence number with the help of the counter in stat_com */ + seq = (fcnt + zr->jpg_err_seq) & 0xff; + dif = (seq - zr->jpg_seq_num) & 0xff; + zr->jpg_seq_num += dif; + } + buf->vbuf.sequence = zr->jpg_settings.tmp_dcm == + 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num; + zr->inuse[i] = NULL; + if (zr->jpg_settings.tmp_dcm != 1) + buf->vbuf.field = zr->jpg_settings.odd_even ? + V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; + else + buf->vbuf.field = zr->jpg_settings.odd_even ? + V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT; + vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_DONE); + + zr->jpg_dma_tail++; + } + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); +} + +irqreturn_t zoran_irq(int irq, void *dev_id) +{ + struct zoran *zr = dev_id; + u32 stat, astat; + + stat = count_reset_interrupt(zr); + astat = stat & IRQ_MASK; + if (astat & zr->card.vsync_int) { + if (zr->running == ZORAN_MAP_MODE_RAW) { + if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SNAP_SHOT) == 0) + pci_warn(zr->pci_dev, "BuzIRQ with SnapShot off ???\n"); + if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FRAME_GRAB) == 0) + zr_set_buf(zr); + return IRQ_HANDLED; + } + if (astat & ZR36057_ISR_JPEG_REP_IRQ) { + if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS && + zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { + pci_err(zr->pci_dev, "JPG IRQ when not in good mode\n"); + return IRQ_HANDLED; + } + zr->frame_num++; + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + return IRQ_HANDLED; + } + /* unused interrupts */ + } + zr->ghost_int++; + return IRQ_HANDLED; +} + +void zoran_set_pci_master(struct zoran *zr, int set_master) +{ + if (set_master) { + pci_set_master(zr->pci_dev); + } else { + u16 command; + + pci_read_config_word(zr->pci_dev, PCI_COMMAND, &command); + command &= ~PCI_COMMAND_MASTER; + pci_write_config_word(zr->pci_dev, PCI_COMMAND, command); + } +} + +void zoran_init_hardware(struct zoran *zr) +{ + /* Enable bus-mastering */ + zoran_set_pci_master(zr, 1); + + /* Initialize the board */ + if (zr->card.init) + zr->card.init(zr); + + decoder_call(zr, core, init, 0); + decoder_call(zr, video, s_std, zr->norm); + decoder_call(zr, video, s_routing, + zr->card.input[zr->input].muxsel, 0, 0); + + encoder_call(zr, core, init, 0); + encoder_call(zr, video, s_std_output, zr->norm); + encoder_call(zr, video, s_routing, 0, 0, 0); + + /* toggle JPEG codec sleep to sync PLL */ + jpeg_codec_sleep(zr, 1); + jpeg_codec_sleep(zr, 0); + + /* + * set individual interrupt enables (without GIRQ1) + * but don't global enable until zoran_open() + */ + zr36057_init_vfe(zr); + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + + btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts +} + +void zr36057_restart(struct zoran *zr) +{ + btwrite(0, ZR36057_SPGPPCR); + usleep_range(1000, 2000); + btor(ZR36057_SPGPPCR_SOFT_RESET, ZR36057_SPGPPCR); + usleep_range(1000, 2000); + + /* assert P_Reset */ + btwrite(0, ZR36057_JPC); + /* set up GPIO direction - all output */ + btwrite(ZR36057_SPGPPCR_SOFT_RESET | 0, ZR36057_SPGPPCR); + + /* set up GPIO pins and guest bus timing */ + btwrite((0x81 << 24) | 0x8888, ZR36057_GPPGCR1); +} + -- cgit v1.2.3