diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/dt-bindings/clock/rp1.h | 60 | ||||
| -rw-r--r-- | include/dt-bindings/mfd/rp1.h | 235 | ||||
| -rw-r--r-- | include/linux/brcmphy.h | 1 | ||||
| -rw-r--r-- | include/linux/broadcom/bcm2835_smi.h | 391 | ||||
| -rw-r--r-- | include/linux/broadcom/vc_mem.h | 39 | ||||
| -rw-r--r-- | include/linux/gpio/generic.h | 1 | ||||
| -rw-r--r-- | include/linux/irqchip/irq-bcm2836.h | 50 | ||||
| -rw-r--r-- | include/linux/leds.h | 3 | ||||
| -rw-r--r-- | include/linux/microchipphy.h | 8 | ||||
| -rw-r--r-- | include/linux/mmc/card.h | 9 | ||||
| -rw-r--r-- | include/linux/mmc/host.h | 1 | ||||
| -rw-r--r-- | include/linux/mmc/sd.h | 12 | ||||
| -rw-r--r-- | include/linux/pio_instructions.h | 481 | ||||
| -rw-r--r-- | include/linux/pio_rp1.h | 1019 | ||||
| -rw-r--r-- | include/linux/platform_data/dma-bcm2708.h | 143 | ||||
| -rw-r--r-- | include/linux/rp1-firmware.h | 53 | ||||
| -rw-r--r-- | include/linux/rp1_platform.h | 20 | ||||
| -rw-r--r-- | include/linux/usb.h | 755 | ||||
| -rw-r--r-- | include/linux/usb/hcd.h | 7 | ||||
| -rw-r--r-- | include/linux/usb/otg-fsm.h | 2 | ||||
| -rw-r--r-- | include/soc/bcm2835/raspberrypi-firmware.h | 30 | ||||
| -rw-r--r-- | include/uapi/linux/fb.h | 12 | ||||
| -rw-r--r-- | include/uapi/linux/serial_core.h | 3 | ||||
| -rw-r--r-- | include/uapi/misc/rp1_pio_if.h | 227 |
24 files changed, 3150 insertions, 412 deletions
diff --git a/include/dt-bindings/clock/rp1.h b/include/dt-bindings/clock/rp1.h new file mode 100644 index 000000000000..1ebb25f16923 --- /dev/null +++ b/include/dt-bindings/clock/rp1.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 Raspberry Pi Ltd. + */ + +#define RP1_PLL_SYS_CORE 0 +#define RP1_PLL_AUDIO_CORE 1 +#define RP1_PLL_VIDEO_CORE 2 + +#define RP1_PLL_SYS 3 +#define RP1_PLL_AUDIO 4 +#define RP1_PLL_VIDEO 5 + +#define RP1_PLL_SYS_PRI_PH 6 +#define RP1_PLL_SYS_SEC_PH 7 +#define RP1_PLL_AUDIO_PRI_PH 8 + +#define RP1_PLL_SYS_SEC 9 +#define RP1_PLL_AUDIO_SEC 10 +#define RP1_PLL_VIDEO_SEC 11 + +#define RP1_CLK_SYS 12 +#define RP1_CLK_SLOW_SYS 13 +#define RP1_CLK_DMA 14 +#define RP1_CLK_UART 15 +#define RP1_CLK_ETH 16 +#define RP1_CLK_PWM0 17 +#define RP1_CLK_PWM1 18 +#define RP1_CLK_AUDIO_IN 19 +#define RP1_CLK_AUDIO_OUT 20 +#define RP1_CLK_I2S 21 +#define RP1_CLK_MIPI0_CFG 22 +#define RP1_CLK_MIPI1_CFG 23 +#define RP1_CLK_PCIE_AUX 24 +#define RP1_CLK_USBH0_MICROFRAME 25 +#define RP1_CLK_USBH1_MICROFRAME 26 +#define RP1_CLK_USBH0_SUSPEND 27 +#define RP1_CLK_USBH1_SUSPEND 28 +#define RP1_CLK_ETH_TSU 29 +#define RP1_CLK_ADC 30 +#define RP1_CLK_SDIO_TIMER 31 +#define RP1_CLK_SDIO_ALT_SRC 32 +#define RP1_CLK_GP0 33 +#define RP1_CLK_GP1 34 +#define RP1_CLK_GP2 35 +#define RP1_CLK_GP3 36 +#define RP1_CLK_GP4 37 +#define RP1_CLK_GP5 38 +#define RP1_CLK_VEC 39 +#define RP1_CLK_DPI 40 +#define RP1_CLK_MIPI0_DPI 41 +#define RP1_CLK_MIPI1_DPI 42 + +/* Extra PLL output channels - RP1B0 only */ +#define RP1_PLL_VIDEO_PRI_PH 43 +#define RP1_PLL_AUDIO_TERN 44 + +/* MIPI clocks managed by the DSI driver */ +#define RP1_CLK_MIPI0_DSI_BYTECLOCK 45 +#define RP1_CLK_MIPI1_DSI_BYTECLOCK 46 diff --git a/include/dt-bindings/mfd/rp1.h b/include/dt-bindings/mfd/rp1.h new file mode 100644 index 000000000000..80bbfd61b270 --- /dev/null +++ b/include/dt-bindings/mfd/rp1.h @@ -0,0 +1,235 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides constants for the PY MFD. + */ + +#ifndef _RP1_H +#define _RP1_H + +/* Address map */ +#define RP1_SYSINFO_BASE 0x000000 +#define RP1_TBMAN_BASE 0x004000 +#define RP1_SYSCFG_BASE 0x008000 +#define RP1_OTP_BASE 0x00c000 +#define RP1_POWER_BASE 0x010000 +#define RP1_RESETS_BASE 0x014000 +#define RP1_CLOCKS_BANK_DEFAULT_BASE 0x018000 +#define RP1_CLOCKS_BANK_VIDEO_BASE 0x01c000 +#define RP1_PLL_SYS_BASE 0x020000 +#define RP1_PLL_AUDIO_BASE 0x024000 +#define RP1_PLL_VIDEO_BASE 0x028000 +#define RP1_UART0_BASE 0x030000 +#define RP1_UART1_BASE 0x034000 +#define RP1_UART2_BASE 0x038000 +#define RP1_UART3_BASE 0x03c000 +#define RP1_UART4_BASE 0x040000 +#define RP1_UART5_BASE 0x044000 +#define RP1_SPI8_BASE 0x04c000 +#define RP1_SPI0_BASE 0x050000 +#define RP1_SPI1_BASE 0x054000 +#define RP1_SPI2_BASE 0x058000 +#define RP1_SPI3_BASE 0x05c000 +#define RP1_SPI4_BASE 0x060000 +#define RP1_SPI5_BASE 0x064000 +#define RP1_SPI6_BASE 0x068000 +#define RP1_SPI7_BASE 0x06c000 +#define RP1_I2C0_BASE 0x070000 +#define RP1_I2C1_BASE 0x074000 +#define RP1_I2C2_BASE 0x078000 +#define RP1_I2C3_BASE 0x07c000 +#define RP1_I2C4_BASE 0x080000 +#define RP1_I2C5_BASE 0x084000 +#define RP1_I2C6_BASE 0x088000 +#define RP1_AUDIO_IN_BASE 0x090000 +#define RP1_AUDIO_OUT_BASE 0x094000 +#define RP1_PWM0_BASE 0x098000 +#define RP1_PWM1_BASE 0x09c000 +#define RP1_I2S0_BASE 0x0a0000 +#define RP1_I2S1_BASE 0x0a4000 +#define RP1_I2S2_BASE 0x0a8000 +#define RP1_TIMER_BASE 0x0ac000 +#define RP1_SDIO0_APBS_BASE 0x0b0000 +#define RP1_SDIO1_APBS_BASE 0x0b4000 +#define RP1_BUSFABRIC_MONITOR_BASE 0x0c0000 +#define RP1_BUSFABRIC_AXISHIM_BASE 0x0c4000 +#define RP1_ADC_BASE 0x0c8000 +#define RP1_IO_BANK0_BASE 0x0d0000 +#define RP1_IO_BANK1_BASE 0x0d4000 +#define RP1_IO_BANK2_BASE 0x0d8000 +#define RP1_SYS_RIO0_BASE 0x0e0000 +#define RP1_SYS_RIO1_BASE 0x0e4000 +#define RP1_SYS_RIO2_BASE 0x0e8000 +#define RP1_PADS_BANK0_BASE 0x0f0000 +#define RP1_PADS_BANK1_BASE 0x0f4000 +#define RP1_PADS_BANK2_BASE 0x0f8000 +#define RP1_PADS_ETH_BASE 0x0fc000 +#define RP1_ETH_IP_BASE 0x100000 +#define RP1_ETH_CFG_BASE 0x104000 +#define RP1_PCIE_APBS_BASE 0x108000 +#define RP1_MIPI0_CSIDMA_BASE 0x110000 +#define RP1_MIPI0_CSIHOST_BASE 0x114000 +#define RP1_MIPI0_DSIDMA_BASE 0x118000 +#define RP1_MIPI0_DSIHOST_BASE 0x11c000 +#define RP1_MIPI0_MIPICFG_BASE 0x120000 +#define RP1_MIPI0_ISP_BASE 0x124000 +#define RP1_MIPI1_CSIDMA_BASE 0x128000 +#define RP1_MIPI1_CSIHOST_BASE 0x12c000 +#define RP1_MIPI1_DSIDMA_BASE 0x130000 +#define RP1_MIPI1_DSIHOST_BASE 0x134000 +#define RP1_MIPI1_MIPICFG_BASE 0x138000 +#define RP1_MIPI1_ISP_BASE 0x13c000 +#define RP1_VIDEO_OUT_CFG_BASE 0x140000 +#define RP1_VIDEO_OUT_VEC_BASE 0x144000 +#define RP1_VIDEO_OUT_DPI_BASE 0x148000 +#define RP1_XOSC_BASE 0x150000 +#define RP1_WATCHDOG_BASE 0x154000 +#define RP1_DMA_TICK_BASE 0x158000 +#define RP1_SDIO_CLOCKS_BASE 0x15c000 +#define RP1_USBHOST0_APBS_BASE 0x160000 +#define RP1_USBHOST1_APBS_BASE 0x164000 +#define RP1_ROSC0_BASE 0x168000 +#define RP1_ROSC1_BASE 0x16c000 +#define RP1_VBUSCTRL_BASE 0x170000 +#define RP1_TICKS_BASE 0x174000 +#define RP1_PIO_APBS_BASE 0x178000 +#define RP1_SDIO0_AHBLS_BASE 0x180000 +#define RP1_SDIO1_AHBLS_BASE 0x184000 +#define RP1_DMA_BASE 0x188000 +#define RP1_RAM_BASE 0x1c0000 +#define RP1_RAM_SIZE 0x020000 +#define RP1_USBHOST0_AXIS_BASE 0x200000 +#define RP1_USBHOST1_AXIS_BASE 0x300000 +#define RP1_EXAC_BASE 0x400000 + +/* Interrupts */ + +#define RP1_INT_IO_BANK0 0 +#define RP1_INT_IO_BANK1 1 +#define RP1_INT_IO_BANK2 2 +#define RP1_INT_AUDIO_IN 3 +#define RP1_INT_AUDIO_OUT 4 +#define RP1_INT_PWM0 5 +#define RP1_INT_ETH 6 +#define RP1_INT_I2C0 7 +#define RP1_INT_I2C1 8 +#define RP1_INT_I2C2 9 +#define RP1_INT_I2C3 10 +#define RP1_INT_I2C4 11 +#define RP1_INT_I2C5 12 +#define RP1_INT_I2C6 13 +#define RP1_INT_I2S0 14 +#define RP1_INT_I2S1 15 +#define RP1_INT_I2S2 16 +#define RP1_INT_SDIO0 17 +#define RP1_INT_SDIO1 18 +#define RP1_INT_SPI0 19 +#define RP1_INT_SPI1 20 +#define RP1_INT_SPI2 21 +#define RP1_INT_SPI3 22 +#define RP1_INT_SPI4 23 +#define RP1_INT_SPI5 24 +#define RP1_INT_UART0 25 +#define RP1_INT_TIMER_0 26 +#define RP1_INT_TIMER_1 27 +#define RP1_INT_TIMER_2 28 +#define RP1_INT_TIMER_3 29 +#define RP1_INT_USBHOST0 30 +#define RP1_INT_USBHOST0_0 31 +#define RP1_INT_USBHOST0_1 32 +#define RP1_INT_USBHOST0_2 33 +#define RP1_INT_USBHOST0_3 34 +#define RP1_INT_USBHOST1 35 +#define RP1_INT_USBHOST1_0 36 +#define RP1_INT_USBHOST1_1 37 +#define RP1_INT_USBHOST1_2 38 +#define RP1_INT_USBHOST1_3 39 +#define RP1_INT_DMA 40 +#define RP1_INT_PWM1 41 +#define RP1_INT_UART1 42 +#define RP1_INT_UART2 43 +#define RP1_INT_UART3 44 +#define RP1_INT_UART4 45 +#define RP1_INT_UART5 46 +#define RP1_INT_MIPI0 47 +#define RP1_INT_MIPI1 48 +#define RP1_INT_VIDEO_OUT 49 +#define RP1_INT_PIO_0 50 +#define RP1_INT_PIO_1 51 +#define RP1_INT_ADC_FIFO 52 +#define RP1_INT_PCIE_OUT 53 +#define RP1_INT_SPI6 54 +#define RP1_INT_SPI7 55 +#define RP1_INT_SPI8 56 +#define RP1_INT_SYSCFG 58 +#define RP1_INT_CLOCKS_DEFAULT 59 +#define RP1_INT_VBUSCTRL 60 +#define RP1_INT_PROC_MISC 57 +#define RP1_INT_END 61 + +/* DMA peripherals (for pacing) */ +#define RP1_DMA_I2C0_RX 0x0 +#define RP1_DMA_I2C0_TX 0x1 +#define RP1_DMA_I2C1_RX 0x2 +#define RP1_DMA_I2C1_TX 0x3 +#define RP1_DMA_I2C2_RX 0x4 +#define RP1_DMA_I2C2_TX 0x5 +#define RP1_DMA_I2C3_RX 0x6 +#define RP1_DMA_I2C3_TX 0x7 +#define RP1_DMA_I2C4_RX 0x8 +#define RP1_DMA_I2C4_TX 0x9 +#define RP1_DMA_I2C5_RX 0xa +#define RP1_DMA_I2C5_TX 0xb +#define RP1_DMA_SPI0_RX 0xc +#define RP1_DMA_SPI0_TX 0xd +#define RP1_DMA_SPI1_RX 0xe +#define RP1_DMA_SPI1_TX 0xf +#define RP1_DMA_SPI2_RX 0x10 +#define RP1_DMA_SPI2_TX 0x11 +#define RP1_DMA_SPI3_RX 0x12 +#define RP1_DMA_SPI3_TX 0x13 +#define RP1_DMA_SPI4_RX 0x14 +#define RP1_DMA_SPI4_TX 0x15 +#define RP1_DMA_SPI5_RX 0x16 +#define RP1_DMA_SPI5_TX 0x17 +#define RP1_DMA_PWM0 0x18 +#define RP1_DMA_UART0_RX 0x19 +#define RP1_DMA_UART0_TX 0x1a +#define RP1_DMA_AUDIO_IN_CH0 0x1b +#define RP1_DMA_AUDIO_IN_CH1 0x1c +#define RP1_DMA_AUDIO_OUT 0x1d +#define RP1_DMA_PWM1 0x1e +#define RP1_DMA_I2S0_RX 0x1f +#define RP1_DMA_I2S0_TX 0x20 +#define RP1_DMA_I2S1_RX 0x21 +#define RP1_DMA_I2S1_TX 0x22 +#define RP1_DMA_I2S2_RX 0x23 +#define RP1_DMA_I2S2_TX 0x24 +#define RP1_DMA_UART1_RX 0x25 +#define RP1_DMA_UART1_TX 0x26 +#define RP1_DMA_UART2_RX 0x27 +#define RP1_DMA_UART2_TX 0x28 +#define RP1_DMA_UART3_RX 0x29 +#define RP1_DMA_UART3_TX 0x2a +#define RP1_DMA_UART4_RX 0x2b +#define RP1_DMA_UART4_TX 0x2c +#define RP1_DMA_UART5_RX 0x2d +#define RP1_DMA_UART5_TX 0x2e +#define RP1_DMA_ADC 0x2f +#define RP1_DMA_DMA_TICK_TICK0 0x30 +#define RP1_DMA_DMA_TICK_TICK1 0x31 +#define RP1_DMA_SPI6_RX 0x32 +#define RP1_DMA_SPI6_TX 0x33 +#define RP1_DMA_SPI7_RX 0x34 +#define RP1_DMA_SPI7_TX 0x35 +#define RP1_DMA_SPI8_RX 0x36 +#define RP1_DMA_SPI8_TX 0x37 +#define RP1_DMA_PIO_CH0_TX 0x38 +#define RP1_DMA_PIO_CH0_RX 0x39 +#define RP1_DMA_PIO_CH1_TX 0x3a +#define RP1_DMA_PIO_CH1_RX 0x3b +#define RP1_DMA_PIO_CH2_TX 0x3c +#define RP1_DMA_PIO_CH2_RX 0x3d +#define RP1_DMA_PIO_CH3_TX 0x3e +#define RP1_DMA_PIO_CH3_RX 0x3f + +#endif diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h index 115a964f3006..97e6a716740b 100644 --- a/include/linux/brcmphy.h +++ b/include/linux/brcmphy.h @@ -24,6 +24,7 @@ #define PHY_ID_BCM5411 0x00206070 #define PHY_ID_BCM5421 0x002060e0 #define PHY_ID_BCM54210E 0x600d84a0 +#define PHY_ID_BCM54213PE 0x600d84a2 #define PHY_ID_BCM5464 0x002060b0 #define PHY_ID_BCM5461 0x002060c0 #define PHY_ID_BCM54612E 0x03625e60 diff --git a/include/linux/broadcom/bcm2835_smi.h b/include/linux/broadcom/bcm2835_smi.h new file mode 100644 index 000000000000..ee3a75edfc03 --- /dev/null +++ b/include/linux/broadcom/bcm2835_smi.h @@ -0,0 +1,391 @@ +/** + * Declarations and definitions for Broadcom's Secondary Memory Interface + * + * Written by Luke Wren <[email protected]> + * Copyright (c) 2015, Raspberry Pi (Trading) Ltd. + * Copyright (c) 2010-2012 Broadcom. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2, as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BCM2835_SMI_H +#define BCM2835_SMI_H + +#include <linux/ioctl.h> + +#ifndef __KERNEL__ +#include <stdint.h> +#include <stdbool.h> +#endif + +#define BCM2835_SMI_IOC_MAGIC 0x1 +#define BCM2835_SMI_INVALID_HANDLE (~0) + +/* IOCTLs 0x100...0x1ff are not device-specific - we can use them */ +#define BCM2835_SMI_IOC_GET_SETTINGS _IO(BCM2835_SMI_IOC_MAGIC, 0) +#define BCM2835_SMI_IOC_WRITE_SETTINGS _IO(BCM2835_SMI_IOC_MAGIC, 1) +#define BCM2835_SMI_IOC_ADDRESS _IO(BCM2835_SMI_IOC_MAGIC, 2) +#define BCM2835_SMI_IOC_MAX 2 + +#define SMI_WIDTH_8BIT 0 +#define SMI_WIDTH_16BIT 1 +#define SMI_WIDTH_9BIT 2 +#define SMI_WIDTH_18BIT 3 + +/* max number of bytes where DMA will not be used */ +#define DMA_THRESHOLD_BYTES 128 +#define DMA_BOUNCE_BUFFER_SIZE (1024 * 1024 / 2) +#define DMA_BOUNCE_BUFFER_COUNT 3 + + +struct smi_settings { + int data_width; + /* Whether or not to pack multiple SMI transfers into a + single 32 bit FIFO word */ + bool pack_data; + + /* Timing for reads (writes the same but for WE) + * + * OE ----------+ +-------------------- + * | | + * +----------+ + * SD -<==============================>----------- + * SA -<=========================================>- + * <-setup-> <-strobe -> <-hold -> <- pace -> + */ + + int read_setup_time; + int read_hold_time; + int read_pace_time; + int read_strobe_time; + + int write_setup_time; + int write_hold_time; + int write_pace_time; + int write_strobe_time; + + bool dma_enable; /* DREQs */ + bool dma_passthrough_enable; /* External DREQs */ + int dma_read_thresh; + int dma_write_thresh; + int dma_panic_read_thresh; + int dma_panic_write_thresh; +}; + +/**************************************************************************** +* +* Declare exported SMI functions +* +***************************************************************************/ + +#ifdef __KERNEL__ + +#include <linux/dmaengine.h> /* for enum dma_transfer_direction */ +#include <linux/of.h> +#include <linux/semaphore.h> + +struct bcm2835_smi_instance; + +struct bcm2835_smi_bounce_info { + struct semaphore callback_sem; + void *buffer[DMA_BOUNCE_BUFFER_COUNT]; + dma_addr_t phys[DMA_BOUNCE_BUFFER_COUNT]; + struct scatterlist sgl[DMA_BOUNCE_BUFFER_COUNT]; +}; + + +void bcm2835_smi_set_regs_from_settings(struct bcm2835_smi_instance *); + +struct smi_settings *bcm2835_smi_get_settings_from_regs( + struct bcm2835_smi_instance *inst); + +void bcm2835_smi_write_buf( + struct bcm2835_smi_instance *inst, + const void *buf, + size_t n_bytes); + +void bcm2835_smi_read_buf( + struct bcm2835_smi_instance *inst, + void *buf, + size_t n_bytes); + +void bcm2835_smi_set_address(struct bcm2835_smi_instance *inst, + unsigned int address); + +ssize_t bcm2835_smi_user_dma( + struct bcm2835_smi_instance *inst, + enum dma_transfer_direction dma_dir, + char __user *user_ptr, + size_t count, + struct bcm2835_smi_bounce_info **bounce); + +struct bcm2835_smi_instance *bcm2835_smi_get(struct device_node *node); + +#endif /* __KERNEL__ */ + +/**************************************************************** +* +* Implementation-only declarations +* +****************************************************************/ + +#ifdef BCM2835_SMI_IMPLEMENTATION + +/* Clock manager registers for SMI clock: */ +#define CM_SMI_BASE_ADDRESS ((BCM2708_PERI_BASE) + 0x1010b0) +/* Clock manager "password" to protect registers from spurious writes */ +#define CM_PWD (0x5a << 24) + +#define CM_SMI_CTL 0x00 +#define CM_SMI_DIV 0x04 + +#define CM_SMI_CTL_FLIP (1 << 8) +#define CM_SMI_CTL_BUSY (1 << 7) +#define CM_SMI_CTL_KILL (1 << 5) +#define CM_SMI_CTL_ENAB (1 << 4) +#define CM_SMI_CTL_SRC_MASK (0xf) +#define CM_SMI_CTL_SRC_OFFS (0) + +#define CM_SMI_DIV_DIVI_MASK (0xf << 12) +#define CM_SMI_DIV_DIVI_OFFS (12) +#define CM_SMI_DIV_DIVF_MASK (0xff << 4) +#define CM_SMI_DIV_DIVF_OFFS (4) + +/* SMI register mapping:*/ +#define SMI_BASE_ADDRESS ((BCM2708_PERI_BASE) + 0x600000) + +#define SMICS 0x00 /* control + status register */ +#define SMIL 0x04 /* length/count (n external txfers) */ +#define SMIA 0x08 /* address register */ +#define SMID 0x0c /* data register */ +#define SMIDSR0 0x10 /* device 0 read settings */ +#define SMIDSW0 0x14 /* device 0 write settings */ +#define SMIDSR1 0x18 /* device 1 read settings */ +#define SMIDSW1 0x1c /* device 1 write settings */ +#define SMIDSR2 0x20 /* device 2 read settings */ +#define SMIDSW2 0x24 /* device 2 write settings */ +#define SMIDSR3 0x28 /* device 3 read settings */ +#define SMIDSW3 0x2c /* device 3 write settings */ +#define SMIDC 0x30 /* DMA control registers */ +#define SMIDCS 0x34 /* direct control/status register */ +#define SMIDA 0x38 /* direct address register */ +#define SMIDD 0x3c /* direct data registers */ +#define SMIFD 0x40 /* FIFO debug register */ + + + +/* Control and Status register bits: + * SMICS_RXF : RX fifo full: 1 when RX fifo is full + * SMICS_TXE : TX fifo empty: 1 when empty. + * SMICS_RXD : RX fifo contains data: 1 when there is data. + * SMICS_TXD : TX fifo can accept data: 1 when true. + * SMICS_RXR : RX fifo needs reading: 1 when fifo more than 3/4 full, or + * when "DONE" and fifo not emptied. + * SMICS_TXW : TX fifo needs writing: 1 when less than 1/4 full. + * SMICS_AFERR : AXI FIFO error: 1 when fifo read when empty or written + * when full. Write 1 to clear. + * SMICS_EDREQ : 1 when external DREQ received. + * SMICS_PXLDAT : Pixel data: write 1 to enable pixel transfer modes. + * SMICS_SETERR : 1 if there was an error writing to setup regs (e.g. + * tx was in progress). Write 1 to clear. + * SMICS_PVMODE : Set to 1 to enable pixel valve mode. + * SMICS_INTR : Set to 1 to enable interrupt on RX. + * SMICS_INTT : Set to 1 to enable interrupt on TX. + * SMICS_INTD : Set to 1 to enable interrupt on DONE condition. + * SMICS_TEEN : Tear effect mode enabled: Programmed transfers will wait + * for a TE trigger before writing. + * SMICS_PAD1 : Padding settings for external transfers. For writes: the + * number of bytes initially written to the TX fifo that + * SMICS_PAD0 : should be ignored. For reads: the number of bytes that will + * be read before the data, and should be dropped. + * SMICS_WRITE : Transfer direction: 1 = write to external device, 0 = read + * SMICS_CLEAR : Write 1 to clear the FIFOs. + * SMICS_START : Write 1 to start the programmed transfer. + * SMICS_ACTIVE : Reads as 1 when a programmed transfer is underway. + * SMICS_DONE : Reads as 1 when transfer finished. For RX, not set until + * FIFO emptied. + * SMICS_ENABLE : Set to 1 to enable the SMI peripheral, 0 to disable. + */ + +#define SMICS_RXF (1 << 31) +#define SMICS_TXE (1 << 30) +#define SMICS_RXD (1 << 29) +#define SMICS_TXD (1 << 28) +#define SMICS_RXR (1 << 27) +#define SMICS_TXW (1 << 26) +#define SMICS_AFERR (1 << 25) +#define SMICS_EDREQ (1 << 15) +#define SMICS_PXLDAT (1 << 14) +#define SMICS_SETERR (1 << 13) +#define SMICS_PVMODE (1 << 12) +#define SMICS_INTR (1 << 11) +#define SMICS_INTT (1 << 10) +#define SMICS_INTD (1 << 9) +#define SMICS_TEEN (1 << 8) +#define SMICS_PAD1 (1 << 7) +#define SMICS_PAD0 (1 << 6) +#define SMICS_WRITE (1 << 5) +#define SMICS_CLEAR (1 << 4) +#define SMICS_START (1 << 3) +#define SMICS_ACTIVE (1 << 2) +#define SMICS_DONE (1 << 1) +#define SMICS_ENABLE (1 << 0) + +/* Address register bits: */ + +#define SMIA_DEVICE_MASK ((1 << 9) | (1 << 8)) +#define SMIA_DEVICE_OFFS (8) +#define SMIA_ADDR_MASK (0x3f) /* bits 5 -> 0 */ +#define SMIA_ADDR_OFFS (0) + +/* DMA control register bits: + * SMIDC_DMAEN : DMA enable: set 1: DMA requests will be issued. + * SMIDC_DMAP : DMA passthrough: when set to 0, top two data pins are used by + * SMI as usual. When set to 1, the top two pins are used for + * external DREQs: pin 16 read request, 17 write. + * SMIDC_PANIC* : Threshold at which DMA will panic during read/write. + * SMIDC_REQ* : Threshold at which DMA will generate a DREQ. + */ + +#define SMIDC_DMAEN (1 << 28) +#define SMIDC_DMAP (1 << 24) +#define SMIDC_PANICR_MASK (0x3f << 18) +#define SMIDC_PANICR_OFFS (18) +#define SMIDC_PANICW_MASK (0x3f << 12) +#define SMIDC_PANICW_OFFS (12) +#define SMIDC_REQR_MASK (0x3f << 6) +#define SMIDC_REQR_OFFS (6) +#define SMIDC_REQW_MASK (0x3f) +#define SMIDC_REQW_OFFS (0) + +/* Device settings register bits: same for all 4 (or 3?) device register sets. + * Device read settings: + * SMIDSR_RWIDTH : Read transfer width. 00 = 8bit, 01 = 16bit, + * 10 = 18bit, 11 = 9bit. + * SMIDSR_RSETUP : Read setup time: number of core cycles between chip + * select/address and read strobe. Min 1, max 64. + * SMIDSR_MODE68 : 1 for System 68 mode (i.e. enable + direction pins, + * rather than OE + WE pin) + * SMIDSR_FSETUP : If set to 1, setup time only applies to first + * transfer after address change. + * SMIDSR_RHOLD : Number of core cycles between read strobe going + * inactive and CS/address going inactive. Min 1, max 64 + * SMIDSR_RPACEALL : When set to 1, this device's RPACE value will always + * be used for the next transaction, even if it is not + * to this device. + * SMIDSR_RPACE : Number of core cycles spent waiting between CS + * deassert and start of next transfer. Min 1, max 128 + * SMIDSR_RDREQ : 1 = use external DMA request on SD16 to pace reads + * from device. Must also set DMAP in SMICS. + * SMIDSR_RSTROBE : Number of cycles to assert the read strobe. + * min 1, max 128. + */ +#define SMIDSR_RWIDTH_MASK ((1<<31)|(1<<30)) +#define SMIDSR_RWIDTH_OFFS (30) +#define SMIDSR_RSETUP_MASK (0x3f << 24) +#define SMIDSR_RSETUP_OFFS (24) +#define SMIDSR_MODE68 (1 << 23) +#define SMIDSR_FSETUP (1 << 22) +#define SMIDSR_RHOLD_MASK (0x3f << 16) +#define SMIDSR_RHOLD_OFFS (16) +#define SMIDSR_RPACEALL (1 << 15) +#define SMIDSR_RPACE_MASK (0x7f << 8) +#define SMIDSR_RPACE_OFFS (8) +#define SMIDSR_RDREQ (1 << 7) +#define SMIDSR_RSTROBE_MASK (0x7f) +#define SMIDSR_RSTROBE_OFFS (0) + +/* Device write settings: + * SMIDSW_WWIDTH : Write transfer width. 00 = 8bit, 01 = 16bit, + * 10= 18bit, 11 = 9bit. + * SMIDSW_WSETUP : Number of cycles between CS assert and write strobe. + * Min 1, max 64. + * SMIDSW_WFORMAT : Pixel format of input. 0 = 16bit RGB 565, + * 1 = 32bit RGBA 8888 + * SMIDSW_WSWAP : 1 = swap pixel data bits. (Use with SMICS_PXLDAT) + * SMIDSW_WHOLD : Time between WE deassert and CS deassert. 1 to 64 + * SMIDSW_WPACEALL : 1: this device's WPACE will be used for the next + * transfer, regardless of that transfer's device. + * SMIDSW_WPACE : Cycles between CS deassert and next CS assert. + * Min 1, max 128 + * SMIDSW_WDREQ : Use external DREQ on pin 17 to pace writes. DMAP must + * be set in SMICS. + * SMIDSW_WSTROBE : Number of cycles to assert the write strobe. + * Min 1, max 128 + */ +#define SMIDSW_WWIDTH_MASK ((1<<31)|(1<<30)) +#define SMIDSW_WWIDTH_OFFS (30) +#define SMIDSW_WSETUP_MASK (0x3f << 24) +#define SMIDSW_WSETUP_OFFS (24) +#define SMIDSW_WFORMAT (1 << 23) +#define SMIDSW_WSWAP (1 << 22) +#define SMIDSW_WHOLD_MASK (0x3f << 16) +#define SMIDSW_WHOLD_OFFS (16) +#define SMIDSW_WPACEALL (1 << 15) +#define SMIDSW_WPACE_MASK (0x7f << 8) +#define SMIDSW_WPACE_OFFS (8) +#define SMIDSW_WDREQ (1 << 7) +#define SMIDSW_WSTROBE_MASK (0x7f) +#define SMIDSW_WSTROBE_OFFS (0) + +/* Direct transfer control + status register + * SMIDCS_WRITE : Direction of transfer: 1 -> write, 0 -> read + * SMIDCS_DONE : 1 when a transfer has finished. Write 1 to clear. + * SMIDCS_START : Write 1 to start a transfer, if one is not already underway. + * SMIDCE_ENABLE: Write 1 to enable SMI in direct mode. + */ + +#define SMIDCS_WRITE (1 << 3) +#define SMIDCS_DONE (1 << 2) +#define SMIDCS_START (1 << 1) +#define SMIDCS_ENABLE (1 << 0) + +/* Direct transfer address register + * SMIDA_DEVICE : Indicates which of the device settings banks should be used. + * SMIDA_ADDR : The value to be asserted on the address pins. + */ + +#define SMIDA_DEVICE_MASK ((1<<9)|(1<<8)) +#define SMIDA_DEVICE_OFFS (8) +#define SMIDA_ADDR_MASK (0x3f) +#define SMIDA_ADDR_OFFS (0) + +/* FIFO debug register + * SMIFD_FLVL : The high-tide mark of FIFO count during the most recent txfer + * SMIFD_FCNT : The current FIFO count. + */ +#define SMIFD_FLVL_MASK (0x3f << 8) +#define SMIFD_FLVL_OFFS (8) +#define SMIFD_FCNT_MASK (0x3f) +#define SMIFD_FCNT_OFFS (0) + +#endif /* BCM2835_SMI_IMPLEMENTATION */ + +#endif /* BCM2835_SMI_H */ diff --git a/include/linux/broadcom/vc_mem.h b/include/linux/broadcom/vc_mem.h new file mode 100644 index 000000000000..3c7079237496 --- /dev/null +++ b/include/linux/broadcom/vc_mem.h @@ -0,0 +1,39 @@ +/* + * Copyright 2010 - 2011 Broadcom Corporation. All rights reserved. + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2, available at + * http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a + * license other than the GPL, without Broadcom's express prior written + * consent. + */ + +#ifndef _VC_MEM_H +#define _VC_MEM_H + +#include <linux/ioctl.h> + +#define VC_MEM_IOC_MAGIC 'v' + +#define VC_MEM_IOC_MEM_PHYS_ADDR _IOR(VC_MEM_IOC_MAGIC, 0, unsigned long) +#define VC_MEM_IOC_MEM_SIZE _IOR(VC_MEM_IOC_MAGIC, 1, unsigned int) +#define VC_MEM_IOC_MEM_BASE _IOR(VC_MEM_IOC_MAGIC, 2, unsigned int) +#define VC_MEM_IOC_MEM_LOAD _IOR(VC_MEM_IOC_MAGIC, 3, unsigned int) + +#ifdef __KERNEL__ +#define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF + +extern unsigned long mm_vc_mem_phys_addr; +extern unsigned int mm_vc_mem_size; +extern int vc_mem_get_current_size(void); +#endif + +#ifdef CONFIG_COMPAT +#define VC_MEM_IOC_MEM_PHYS_ADDR32 _IOR(VC_MEM_IOC_MAGIC, 0, compat_ulong_t) +#endif + +#endif /* _VC_MEM_H */ diff --git a/include/linux/gpio/generic.h b/include/linux/gpio/generic.h index ff566dc9c3cb..e3625f4cb933 100644 --- a/include/linux/gpio/generic.h +++ b/include/linux/gpio/generic.h @@ -18,6 +18,7 @@ struct device; #define GPIO_GENERIC_NO_SET_ON_INPUT BIT(6) #define GPIO_GENERIC_PINCTRL_BACKEND BIT(7) /* Call pinctrl direction setters */ #define GPIO_GENERIC_NO_INPUT BIT(8) /* only output */ +#define GPIO_GENERIC_REG_DIRECT BIT(15) /* ignore shadow registers */ /** * struct gpio_generic_chip_config - Generic GPIO chip configuration data diff --git a/include/linux/irqchip/irq-bcm2836.h b/include/linux/irqchip/irq-bcm2836.h index ac5719d8f56b..0d105aee10fa 100644 --- a/include/linux/irqchip/irq-bcm2836.h +++ b/include/linux/irqchip/irq-bcm2836.h @@ -5,57 +5,59 @@ * Copyright 2015 Broadcom */ -#define LOCAL_CONTROL 0x000 -#define LOCAL_PRESCALER 0x008 +#define LOCAL_CONTROL 0x000 +#define LOCAL_PRESCALER 0x008 /* * The low 2 bits identify the CPU that the GPU IRQ goes to, and the * next 2 bits identify the CPU that the GPU FIQ goes to. */ -#define LOCAL_GPU_ROUTING 0x00c +#define LOCAL_GPU_ROUTING 0x00c /* When setting bits 0-3, enables PMU interrupts on that CPU. */ -#define LOCAL_PM_ROUTING_SET 0x010 +#define LOCAL_PM_ROUTING_SET 0x010 /* When setting bits 0-3, disables PMU interrupts on that CPU. */ -#define LOCAL_PM_ROUTING_CLR 0x014 +#define LOCAL_PM_ROUTING_CLR 0x014 /* * The low 4 bits of this are the CPU's timer IRQ enables, and the * next 4 bits are the CPU's timer FIQ enables (which override the IRQ * bits). */ -#define LOCAL_TIMER_INT_CONTROL0 0x040 +#define LOCAL_TIMER_INT_CONTROL0 0x040 /* * The low 4 bits of this are the CPU's per-mailbox IRQ enables, and * the next 4 bits are the CPU's per-mailbox FIQ enables (which * override the IRQ bits). */ -#define LOCAL_MAILBOX_INT_CONTROL0 0x050 +#define LOCAL_MAILBOX_INT_CONTROL0 0x050 /* * The CPU's interrupt status register. Bits are defined by the * LOCAL_IRQ_* bits below. */ -#define LOCAL_IRQ_PENDING0 0x060 +#define LOCAL_IRQ_PENDING0 0x060 /* Same status bits as above, but for FIQ. */ -#define LOCAL_FIQ_PENDING0 0x070 +#define LOCAL_FIQ_PENDING0 0x070 /* * Mailbox write-to-set bits. There are 16 mailboxes, 4 per CPU, and * these bits are organized by mailbox number and then CPU number. We * use mailbox 0 for IPIs. The mailbox's interrupt is raised while * any bit is set. */ -#define LOCAL_MAILBOX0_SET0 0x080 -#define LOCAL_MAILBOX3_SET0 0x08c +#define LOCAL_MAILBOX0_SET0 0x080 +#define LOCAL_MAILBOX3_SET0 0x08c /* Mailbox write-to-clear bits. */ -#define LOCAL_MAILBOX0_CLR0 0x0c0 -#define LOCAL_MAILBOX3_CLR0 0x0cc +#define LOCAL_MAILBOX0_CLR0 0x0c0 +#define LOCAL_MAILBOX3_CLR0 0x0cc -#define LOCAL_IRQ_CNTPSIRQ 0 -#define LOCAL_IRQ_CNTPNSIRQ 1 -#define LOCAL_IRQ_CNTHPIRQ 2 -#define LOCAL_IRQ_CNTVIRQ 3 -#define LOCAL_IRQ_MAILBOX0 4 -#define LOCAL_IRQ_MAILBOX1 5 -#define LOCAL_IRQ_MAILBOX2 6 -#define LOCAL_IRQ_MAILBOX3 7 -#define LOCAL_IRQ_GPU_FAST 8 -#define LOCAL_IRQ_PMU_FAST 9 -#define LAST_IRQ LOCAL_IRQ_PMU_FAST +#define LOCAL_IRQ_CNTPSIRQ 0 +#define LOCAL_IRQ_CNTPNSIRQ 1 +#define LOCAL_IRQ_CNTHPIRQ 2 +#define LOCAL_IRQ_CNTVIRQ 3 +#define LOCAL_IRQ_MAILBOX0 4 +#define LOCAL_IRQ_MAILBOX1 5 +#define LOCAL_IRQ_MAILBOX2 6 +#define LOCAL_IRQ_MAILBOX3 7 +#define LOCAL_IRQ_GPU_FAST 8 +#define LOCAL_IRQ_PMU_FAST 9 +#define LAST_IRQ LOCAL_IRQ_PMU_FAST + +void bcm2836_arm_irqchip_spin_gpu_irq(void);
\ No newline at end of file diff --git a/include/linux/leds.h b/include/linux/leds.h index b16b803cc1ac..4dff7add72ce 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -109,6 +109,9 @@ struct led_classdev { #define LED_INIT_DEFAULT_TRIGGER BIT(23) #define LED_REJECT_NAME_CONFLICT BIT(24) #define LED_MULTI_COLOR BIT(25) + /* Additions for Raspberry Pi PWR LED */ +#define SET_GPIO_INPUT BIT(30) +#define SET_GPIO_OUTPUT BIT(31) /* set_brightness_work / blink_timer flags, atomic, private. */ unsigned long work_flags; diff --git a/include/linux/microchipphy.h b/include/linux/microchipphy.h index 517288da19fd..626c450d71f4 100644 --- a/include/linux/microchipphy.h +++ b/include/linux/microchipphy.h @@ -61,6 +61,14 @@ /* Registers specific to the LAN7800/LAN7850 embedded phy */ #define LAN78XX_PHY_LED_MODE_SELECT (0x1D) +#define LAN78XX_PHY_CTRL3 (0x14) +#define LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT (0x0010) +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK (0x000c) +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2 (0x0000) +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3 (0x0004) +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4 (0x0008) +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5 (0x000c) + /* DSP registers */ #define PHY_ARDENNES_MMD_DEV_3_PHY_CFG (0x806A) #define PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_ (0x2000) diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index ddcdf23d731c..221fef5c9715 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -329,9 +329,11 @@ struct mmc_card { #define MMC_QUIRK_BROKEN_SD_CACHE (1<<15) /* Disable broken SD cache support */ #define MMC_QUIRK_BROKEN_CACHE_FLUSH (1<<16) /* Don't flush cache until the write has occurred */ #define MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY (1<<17) /* Disable broken SD poweroff notify support */ -#define MMC_QUIRK_NO_UHS_DDR50_TUNING (1<<18) /* Disable DDR50 tuning */ +#define MMC_QUIRK_NO_UHS_DDR50_TUNING (1 << 18) /* Disable DDR50 tuning */ +#define MMC_QUIRK_WORKING_SD_CQ (1<<30) /* SD card has known-good CQ implementation */ +#define MMC_QUIRK_ERASE_BROKEN (1<<31) /* Skip erase */ - bool written_flag; /* Indicates eMMC has been written since power on */ + bool written_flag; /* Indicates eMMC has been written since power on */ bool reenable_cmdq; /* Re-enable Command Queue */ unsigned int erase_size; /* erase size in sectors */ @@ -354,6 +356,7 @@ struct mmc_card { struct sd_switch_caps sw_caps; /* switch (CMD6) caps */ struct sd_ext_reg ext_power; /* SD extension reg for PM */ struct sd_ext_reg ext_perf; /* SD extension reg for PERF */ + u8 *ext_reg_buf; /* 512 byte block for extension register R/W */ struct sd_uhs2_config uhs2_config; /* SD UHS-II config */ @@ -378,6 +381,8 @@ struct mmc_card { unsigned int nr_parts; struct workqueue_struct *complete_wq; /* Private workqueue */ + + unsigned int max_posted_writes; /* command queue posted write limit */ }; static inline bool mmc_large_sector(struct mmc_card *card) diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index e0e2c265e5d1..37b33ea3b037 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -463,6 +463,7 @@ struct mmc_host { #define MMC_CAP2_CRYPTO 0 #endif #define MMC_CAP2_ALT_GPT_TEGRA (1 << 28) /* Host with eMMC that has GPT entry at a non-standard location */ +#define MMC_CAP2_SD_CQE_PERMISSIVE (1 << 31) /* Ignore allow-list for CQ capable SD card detection */ bool uhs2_sd_tran; /* UHS-II flag for SD_TRAN state */ bool uhs2_app_cmd; /* UHS-II flag for APP command */ diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h index af5fc70e09a2..c13b565c6f01 100644 --- a/include/linux/mmc/sd.h +++ b/include/linux/mmc/sd.h @@ -32,6 +32,9 @@ #define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ #define SD_APP_SEND_SCR 51 /* adtc R1 */ + /* class 1 */ +#define SD_CMDQ_TASK_MGMT 43 /* ac See below R1b */ + /* class 11 */ #define SD_READ_EXTR_SINGLE 48 /* adtc [31:0] R1 */ #define SD_WRITE_EXTR_SINGLE 49 /* adtc [31:0] R1 */ @@ -65,6 +68,15 @@ */ /* + * SD_CMDQ_TASK_MGMT argument format: + * + * [31:21] Reserved (0) + * [20:16] Task ID + * [15:4] Reserved (0) + * [3:0] Operation - 0x1 = abort all tasks, 0x2 = abort Task ID + */ + +/* * SCR field definitions */ diff --git a/include/linux/pio_instructions.h b/include/linux/pio_instructions.h new file mode 100644 index 000000000000..a72934b1ed60 --- /dev/null +++ b/include/linux/pio_instructions.h @@ -0,0 +1,481 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + */ + +#ifndef _HARDWARE_PIO_INSTRUCTIONS_H +#define _HARDWARE_PIO_INSTRUCTIONS_H + +/** \brief PIO instruction encoding + * \defgroup pio_instructions pio_instructions + * \ingroup hardware_pio + * + * Functions for generating PIO instruction encodings programmatically. In debug builds + *`PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS` can be set to 1 to enable validation of encoding function + * parameters. + * + * For fuller descriptions of the instructions in question see the "RP2040 Datasheet" + */ + +// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS, Enable/disable assertions in the PIO instructions, type=bool, default=0, group=pio_instructions +#ifndef PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS +#define PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +enum pio_instr_bits { + pio_instr_bits_jmp = 0x0000, + pio_instr_bits_wait = 0x2000, + pio_instr_bits_in = 0x4000, + pio_instr_bits_out = 0x6000, + pio_instr_bits_push = 0x8000, + pio_instr_bits_pull = 0x8080, + pio_instr_bits_mov = 0xa000, + pio_instr_bits_irq = 0xc000, + pio_instr_bits_set = 0xe000, +}; + +#ifndef NDEBUG +#define _PIO_INVALID_IN_SRC 0x08u +#define _PIO_INVALID_OUT_DEST 0x10u +#define _PIO_INVALID_SET_DEST 0x20u +#define _PIO_INVALID_MOV_SRC 0x40u +#define _PIO_INVALID_MOV_DEST 0x80u +#else +#define _PIO_INVALID_IN_SRC 0u +#define _PIO_INVALID_OUT_DEST 0u +#define _PIO_INVALID_SET_DEST 0u +#define _PIO_INVALID_MOV_SRC 0u +#define _PIO_INVALID_MOV_DEST 0u +#endif + +/*! \brief Enumeration of values to pass for source/destination args for instruction encoding functions + * \ingroup pio_instructions + * + * \note Not all values are suitable for all functions. Validity is only checked in debug mode when + * `PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS` is 1 + */ +enum pio_src_dest { + pio_pins = 0u, + pio_x = 1u, + pio_y = 2u, + pio_null = 3u | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST, + pio_pindirs = 4u | _PIO_INVALID_IN_SRC | _PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST, + pio_exec_mov = 4u | _PIO_INVALID_IN_SRC | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC, + pio_status = 5u | _PIO_INVALID_IN_SRC | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST, + pio_pc = 5u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC, + pio_isr = 6u | _PIO_INVALID_SET_DEST, + pio_osr = 7u | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST, + pio_exec_out = 7u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST, +}; + +static inline uint _pio_major_instr_bits(uint instr) { + return instr & 0xe000u; +} + +static inline uint _pio_encode_instr_and_args(enum pio_instr_bits instr_bits, uint arg1, uint arg2) { + valid_params_if(PIO_INSTRUCTIONS, arg1 <= 0x7); +#if PARAM_ASSERTIONS_ENABLED(PIO_INSTRUCTIONS) + uint32_t major = _pio_major_instr_bits(instr_bits); + if (major == pio_instr_bits_in || major == pio_instr_bits_out) { + assert(arg2 && arg2 <= 32); + } else { + assert(arg2 <= 31); + } +#endif + return instr_bits | (arg1 << 5u) | (arg2 & 0x1fu); +} + +static inline uint _pio_encode_instr_and_src_dest(enum pio_instr_bits instr_bits, enum pio_src_dest dest, uint value) { + return _pio_encode_instr_and_args(instr_bits, dest & 7u, value); +} + +/*! \brief Encode just the delay slot bits of an instruction + * \ingroup pio_instructions + * + * \note This function does not return a valid instruction encoding; instead it returns an encoding of the delay + * slot suitable for `OR`ing with the result of an encoding function for an actual instruction. Care should be taken when + * combining the results of this function with the results of \ref pio_encode_sideset and \ref pio_encode_sideset_opt + * as they share the same bits within the instruction encoding. + * + * \param cycles the number of cycles 0-31 (or less if side set is being used) + * \return the delay slot bits to be ORed with an instruction encoding + */ +static inline uint pio_encode_delay(uint cycles) { + // note that the maximum cycles will be smaller if sideset_bit_count > 0 + valid_params_if(PIO_INSTRUCTIONS, cycles <= 0x1f); + return cycles << 8u; +} + +/*! \brief Encode just the side set bits of an instruction (in non optional side set mode) + * \ingroup pio_instructions + * + * \note This function does not return a valid instruction encoding; instead it returns an encoding of the side set bits + * suitable for `OR`ing with the result of an encoding function for an actual instruction. Care should be taken when + * combining the results of this function with the results of \ref pio_encode_delay as they share the same bits + * within the instruction encoding. + * + * \param sideset_bit_count number of side set bits as would be specified via `.sideset` in pioasm + * \param value the value to sideset on the pins + * \return the side set bits to be ORed with an instruction encoding + */ +static inline uint pio_encode_sideset(uint sideset_bit_count, uint value) { + valid_params_if(PIO_INSTRUCTIONS, sideset_bit_count >= 1 && sideset_bit_count <= 5); + valid_params_if(PIO_INSTRUCTIONS, value <= ((1u << sideset_bit_count) - 1)); + return value << (13u - sideset_bit_count); +} + +/*! \brief Encode just the side set bits of an instruction (in optional -`opt` side set mode) + * \ingroup pio_instructions + * + * \note This function does not return a valid instruction encoding; instead it returns an encoding of the side set bits + * suitable for `OR`ing with the result of an encoding function for an actual instruction. Care should be taken when + * combining the results of this function with the results of \ref pio_encode_delay as they share the same bits + * within the instruction encoding. + * + * \param sideset_bit_count number of side set bits as would be specified via `.sideset <n> opt` in pioasm + * \param value the value to sideset on the pins + * \return the side set bits to be ORed with an instruction encoding + */ +static inline uint pio_encode_sideset_opt(uint sideset_bit_count, uint value) { + valid_params_if(PIO_INSTRUCTIONS, sideset_bit_count >= 1 && sideset_bit_count <= 4); + valid_params_if(PIO_INSTRUCTIONS, value <= ((1u << sideset_bit_count) - 1)); + return 0x1000u | value << (12u - sideset_bit_count); +} + +/*! \brief Encode an unconditional JMP instruction + * \ingroup pio_instructions + * + * This is the equivalent of `JMP <addr>` + * + * \param addr The target address 0-31 (an absolute address within the PIO instruction memory) + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_jmp(uint addr) { + return _pio_encode_instr_and_args(pio_instr_bits_jmp, 0, addr); +} + +/*! \brief Encode a conditional JMP if scratch X zero instruction + * \ingroup pio_instructions + * + * This is the equivalent of `JMP !X <addr>` + * + * \param addr The target address 0-31 (an absolute address within the PIO instruction memory) + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_jmp_not_x(uint addr) { + return _pio_encode_instr_and_args(pio_instr_bits_jmp, 1, addr); +} + +/*! \brief Encode a conditional JMP if scratch X non-zero (and post-decrement X) instruction + * \ingroup pio_instructions + * + * This is the equivalent of `JMP X-- <addr>` + * + * \param addr The target address 0-31 (an absolute address within the PIO instruction memory) + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_jmp_x_dec(uint addr) { + return _pio_encode_instr_and_args(pio_instr_bits_jmp, 2, addr); +} + +/*! \brief Encode a conditional JMP if scratch Y zero instruction + * \ingroup pio_instructions + * + * This is the equivalent of `JMP !Y <addr>` + * + * \param addr The target address 0-31 (an absolute address within the PIO instruction memory) + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_jmp_not_y(uint addr) { + return _pio_encode_instr_and_args(pio_instr_bits_jmp, 3, addr); +} + +/*! \brief Encode a conditional JMP if scratch Y non-zero (and post-decrement Y) instruction + * \ingroup pio_instructions + * + * This is the equivalent of `JMP Y-- <addr>` + * + * \param addr The target address 0-31 (an absolute address within the PIO instruction memory) + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_jmp_y_dec(uint addr) { + return _pio_encode_instr_and_args(pio_instr_bits_jmp, 4, addr); +} + +/*! \brief Encode a conditional JMP if scratch X not equal scratch Y instruction + * \ingroup pio_instructions + * + * This is the equivalent of `JMP X!=Y <addr>` + * + * \param addr The target address 0-31 (an absolute address within the PIO instruction memory) + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_jmp_x_ne_y(uint addr) { + return _pio_encode_instr_and_args(pio_instr_bits_jmp, 5, addr); +} + +/*! \brief Encode a conditional JMP if input pin high instruction + * \ingroup pio_instructions + * + * This is the equivalent of `JMP PIN <addr>` + * + * \param addr The target address 0-31 (an absolute address within the PIO instruction memory) + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_jmp_pin(uint addr) { + return _pio_encode_instr_and_args(pio_instr_bits_jmp, 6, addr); +} + +/*! \brief Encode a conditional JMP if output shift register not empty instruction + * \ingroup pio_instructions + * + * This is the equivalent of `JMP !OSRE <addr>` + * + * \param addr The target address 0-31 (an absolute address within the PIO instruction memory) + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_jmp_not_osre(uint addr) { + return _pio_encode_instr_and_args(pio_instr_bits_jmp, 7, addr); +} + +static inline uint _pio_encode_irq(bool relative, uint irq) { + valid_params_if(PIO_INSTRUCTIONS, irq <= 7); + return (relative ? 0x10u : 0x0u) | irq; +} + +/*! \brief Encode a WAIT for GPIO pin instruction + * \ingroup pio_instructions + * + * This is the equivalent of `WAIT <polarity> GPIO <gpio>` + * + * \param polarity true for `WAIT 1`, false for `WAIT 0` + * \param gpio The real GPIO number 0-31 + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_wait_gpio(bool polarity, uint gpio) { + return _pio_encode_instr_and_args(pio_instr_bits_wait, 0u | (polarity ? 4u : 0u), gpio); +} + +/*! \brief Encode a WAIT for pin instruction + * \ingroup pio_instructions + * + * This is the equivalent of `WAIT <polarity> PIN <pin>` + * + * \param polarity true for `WAIT 1`, false for `WAIT 0` + * \param pin The pin number 0-31 relative to the executing SM's input pin mapping + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_wait_pin(bool polarity, uint pin) { + return _pio_encode_instr_and_args(pio_instr_bits_wait, 1u | (polarity ? 4u : 0u), pin); +} + +/*! \brief Encode a WAIT for IRQ instruction + * \ingroup pio_instructions + * + * This is the equivalent of `WAIT <polarity> IRQ <irq> <relative>` + * + * \param polarity true for `WAIT 1`, false for `WAIT 0` + * \param relative true for a `WAIT IRQ <irq> REL`, false for regular `WAIT IRQ <irq>` + * \param irq the irq number 0-7 + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_wait_irq(bool polarity, bool relative, uint irq) { + valid_params_if(PIO_INSTRUCTIONS, irq <= 7); + return _pio_encode_instr_and_args(pio_instr_bits_wait, 2u | (polarity ? 4u : 0u), _pio_encode_irq(relative, irq)); +} + +/*! \brief Encode an IN instruction + * \ingroup pio_instructions + * + * This is the equivalent of `IN <src>, <count>` + * + * \param src The source to take data from + * \param count The number of bits 1-32 + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_in(enum pio_src_dest src, uint count) { + valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_IN_SRC)); + return _pio_encode_instr_and_src_dest(pio_instr_bits_in, src, count); +} + +/*! \brief Encode an OUT instruction + * \ingroup pio_instructions + * + * This is the equivalent of `OUT <src>, <count>` + * + * \param dest The destination to write data to + * \param count The number of bits 1-32 + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_out(enum pio_src_dest dest, uint count) { + valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_OUT_DEST)); + return _pio_encode_instr_and_src_dest(pio_instr_bits_out, dest, count); +} + +/*! \brief Encode a PUSH instruction + * \ingroup pio_instructions + * + * This is the equivalent of `PUSH <if_full>, <block>` + * + * \param if_full true for `PUSH IF_FULL ...`, false for `PUSH ...` + * \param block true for `PUSH ... BLOCK`, false for `PUSH ...` + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_push(bool if_full, bool block) { + return _pio_encode_instr_and_args(pio_instr_bits_push, (if_full ? 2u : 0u) | (block ? 1u : 0u), 0); +} + +/*! \brief Encode a PULL instruction + * \ingroup pio_instructions + * + * This is the equivalent of `PULL <if_empty>, <block>` + * + * \param if_empty true for `PULL IF_EMPTY ...`, false for `PULL ...` + * \param block true for `PULL ... BLOCK`, false for `PULL ...` + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_pull(bool if_empty, bool block) { + return _pio_encode_instr_and_args(pio_instr_bits_pull, (if_empty ? 2u : 0u) | (block ? 1u : 0u), 0); +} + +/*! \brief Encode a MOV instruction + * \ingroup pio_instructions + * + * This is the equivalent of `MOV <dest>, <src>` + * + * \param dest The destination to write data to + * \param src The source to take data from + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_mov(enum pio_src_dest dest, enum pio_src_dest src) { + valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_MOV_DEST)); + valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_MOV_SRC)); + return _pio_encode_instr_and_src_dest(pio_instr_bits_mov, dest, src & 7u); +} + +/*! \brief Encode a MOV instruction with bit invert + * \ingroup pio_instructions + * + * This is the equivalent of `MOV <dest>, ~<src>` + * + * \param dest The destination to write inverted data to + * \param src The source to take data from + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_mov_not(enum pio_src_dest dest, enum pio_src_dest src) { + valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_MOV_DEST)); + valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_MOV_SRC)); + return _pio_encode_instr_and_src_dest(pio_instr_bits_mov, dest, (1u << 3u) | (src & 7u)); +} + +/*! \brief Encode a MOV instruction with bit reverse + * \ingroup pio_instructions + * + * This is the equivalent of `MOV <dest>, ::<src>` + * + * \param dest The destination to write bit reversed data to + * \param src The source to take data from + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_mov_reverse(enum pio_src_dest dest, enum pio_src_dest src) { + valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_MOV_DEST)); + valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_MOV_SRC)); + return _pio_encode_instr_and_src_dest(pio_instr_bits_mov, dest, (2u << 3u) | (src & 7u)); +} + +/*! \brief Encode a IRQ SET instruction + * \ingroup pio_instructions + * + * This is the equivalent of `IRQ SET <irq> <relative>` + * + * \param relative true for a `IRQ SET <irq> REL`, false for regular `IRQ SET <irq>` + * \param irq the irq number 0-7 + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_irq_set(bool relative, uint irq) { + return _pio_encode_instr_and_args(pio_instr_bits_irq, 0, _pio_encode_irq(relative, irq)); +} + +/*! \brief Encode a IRQ WAIT instruction + * \ingroup pio_instructions + * + * This is the equivalent of `IRQ WAIT <irq> <relative>` + * + * \param relative true for a `IRQ WAIT <irq> REL`, false for regular `IRQ WAIT <irq>` + * \param irq the irq number 0-7 + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_irq_wait(bool relative, uint irq) { + return _pio_encode_instr_and_args(pio_instr_bits_irq, 1, _pio_encode_irq(relative, irq)); +} + +/*! \brief Encode a IRQ CLEAR instruction + * \ingroup pio_instructions + * + * This is the equivalent of `IRQ CLEAR <irq> <relative>` + * + * \param relative true for a `IRQ CLEAR <irq> REL`, false for regular `IRQ CLEAR <irq>` + * \param irq the irq number 0-7 + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_irq_clear(bool relative, uint irq) { + return _pio_encode_instr_and_args(pio_instr_bits_irq, 2, _pio_encode_irq(relative, irq)); +} + +/*! \brief Encode a SET instruction + * \ingroup pio_instructions + * + * This is the equivalent of `SET <dest>, <value>` + * + * \param dest The destination to apply the value to + * \param value The value 0-31 + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_set(enum pio_src_dest dest, uint value) { + valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_SET_DEST)); + return _pio_encode_instr_and_src_dest(pio_instr_bits_set, dest, value); +} + +/*! \brief Encode a NOP instruction + * \ingroup pio_instructions + * + * This is the equivalent of `NOP` which is itself encoded as `MOV y, y` + * + * \return The instruction encoding with 0 delay and no side set value + * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt + */ +static inline uint pio_encode_nop(void) { + return pio_encode_mov(pio_y, pio_y); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/linux/pio_rp1.h b/include/linux/pio_rp1.h new file mode 100644 index 000000000000..f262fdd9c8f1 --- /dev/null +++ b/include/linux/pio_rp1.h @@ -0,0 +1,1019 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 Raspberry Pi Ltd. + * All rights reserved. + */ + +#ifndef _PIO_RP1_H +#define _PIO_RP1_H + +#include <uapi/misc/rp1_pio_if.h> + +#define PARAM_WARNINGS_ENABLED 1 + +#ifdef DEBUG +#define PARAM_WARNINGS_ENABLED 1 +#endif + +#ifndef PARAM_WARNINGS_ENABLED +#define PARAM_WARNINGS_ENABLED 0 +#endif + +#define bad_params_if(client, test) \ + ({ bool f = (test); if (f && client) pio_set_error(client, -EINVAL); \ + if (f && PARAM_WARNINGS_ENABLED) WARN_ON((test)); \ + f; }) + +#ifndef PARAM_ASSERTIONS_ENABLE_ALL +#define PARAM_ASSERTIONS_ENABLE_ALL 0 +#endif + +#ifndef PARAM_ASSERTIONS_DISABLE_ALL +#define PARAM_ASSERTIONS_DISABLE_ALL 0 +#endif + +#define PARAM_ASSERTIONS_ENABLED(x) \ + ((PARAM_ASSERTIONS_ENABLED_ ## x || PARAM_ASSERTIONS_ENABLE_ALL) && \ + !PARAM_ASSERTIONS_DISABLE_ALL) +#define valid_params_if(x, test) ({if (PARAM_ASSERTIONS_ENABLED(x)) WARN_ON(test); }) + +#include <linux/pio_instructions.h> + +#define NUM_PIO_STATE_MACHINES 4 +#define PIO_INSTRUCTION_COUNT 32 +#define PIO_ORIGIN_ANY ((uint)(~0)) +#define GPIOS_MASK ((1 << RP1_PIO_GPIO_COUNT) - 1) + +#define PICO_NO_HARDWARE 0 + +#define pio0 pio_open_helper(0) + +#define PROC_PIO_SM0_PINCTRL_OUT_BASE_BITS 0x0000001f +#define PROC_PIO_SM0_PINCTRL_OUT_BASE_LSB 0 +#define PROC_PIO_SM0_PINCTRL_OUT_COUNT_BITS 0x03f00000 +#define PROC_PIO_SM0_PINCTRL_OUT_COUNT_LSB 20 +#define PROC_PIO_SM0_PINCTRL_SET_BASE_BITS 0x000003e0 +#define PROC_PIO_SM0_PINCTRL_SET_BASE_LSB 5 +#define PROC_PIO_SM0_PINCTRL_SET_COUNT_BITS 0x1c000000 +#define PROC_PIO_SM0_PINCTRL_SET_COUNT_LSB 26 +#define PROC_PIO_SM0_PINCTRL_IN_BASE_BITS 0x000f8000 +#define PROC_PIO_SM0_PINCTRL_IN_BASE_LSB 15 +#define PROC_PIO_SM0_PINCTRL_SIDESET_BASE_BITS 0x00007c00 +#define PROC_PIO_SM0_PINCTRL_SIDESET_BASE_LSB 10 +#define PROC_PIO_SM0_PINCTRL_SIDESET_COUNT_BITS 0xe0000000 +#define PROC_PIO_SM0_PINCTRL_SIDESET_COUNT_LSB 29 +#define PROC_PIO_SM0_EXECCTRL_SIDE_EN_BITS 0x40000000 +#define PROC_PIO_SM0_EXECCTRL_SIDE_EN_LSB 30 +#define PROC_PIO_SM0_EXECCTRL_SIDE_PINDIR_BITS 0x20000000 +#define PROC_PIO_SM0_EXECCTRL_SIDE_PINDIR_LSB 29 +#define PROC_PIO_SM0_CLKDIV_INT_LSB 16 +#define PROC_PIO_SM0_CLKDIV_FRAC_LSB 8 +#define PROC_PIO_SM0_EXECCTRL_WRAP_TOP_BITS 0x0001f000 +#define PROC_PIO_SM0_EXECCTRL_WRAP_TOP_LSB 12 +#define PROC_PIO_SM0_EXECCTRL_WRAP_BOTTOM_BITS 0x00000f80 +#define PROC_PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB 7 +#define PROC_PIO_SM0_EXECCTRL_JMP_PIN_BITS 0x1f000000 +#define PROC_PIO_SM0_EXECCTRL_JMP_PIN_LSB 24 +#define PROC_PIO_SM0_SHIFTCTRL_IN_SHIFTDIR_BITS 0x00040000 +#define PROC_PIO_SM0_SHIFTCTRL_IN_SHIFTDIR_LSB 18 +#define PROC_PIO_SM0_SHIFTCTRL_AUTOPULL_BITS 0x00020000 +#define PROC_PIO_SM0_SHIFTCTRL_AUTOPULL_LSB 17 +#define PROC_PIO_SM0_SHIFTCTRL_AUTOPUSH_BITS 0x00010000 +#define PROC_PIO_SM0_SHIFTCTRL_AUTOPUSH_LSB 16 +#define PROC_PIO_SM0_SHIFTCTRL_PUSH_THRESH_BITS 0x01f00000 +#define PROC_PIO_SM0_SHIFTCTRL_PUSH_THRESH_LSB 20 +#define PROC_PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_BITS 0x00080000 +#define PROC_PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_LSB 19 +#define PROC_PIO_SM0_SHIFTCTRL_PULL_THRESH_BITS 0x3e000000 +#define PROC_PIO_SM0_SHIFTCTRL_PULL_THRESH_LSB 25 +#define PROC_PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS 0x40000000 +#define PROC_PIO_SM0_SHIFTCTRL_FJOIN_TX_LSB 30 +#define PROC_PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS 0x80000000 +#define PROC_PIO_SM0_SHIFTCTRL_FJOIN_RX_LSB 31 +#define PROC_PIO_SM0_EXECCTRL_OUT_STICKY_BITS 0x00020000 +#define PROC_PIO_SM0_EXECCTRL_OUT_STICKY_LSB 17 +#define PROC_PIO_SM0_EXECCTRL_INLINE_OUT_EN_BITS 0x00040000 +#define PROC_PIO_SM0_EXECCTRL_INLINE_OUT_EN_LSB 18 +#define PROC_PIO_SM0_EXECCTRL_OUT_EN_SEL_BITS 0x00f80000 +#define PROC_PIO_SM0_EXECCTRL_OUT_EN_SEL_LSB 19 +#define PROC_PIO_SM0_EXECCTRL_STATUS_SEL_BITS 0x00000020 +#define PROC_PIO_SM0_EXECCTRL_STATUS_SEL_LSB 5 +#define PROC_PIO_SM0_EXECCTRL_STATUS_N_BITS 0x0000001f +#define PROC_PIO_SM0_EXECCTRL_STATUS_N_LSB 0 + +enum pio_fifo_join { + PIO_FIFO_JOIN_NONE = 0, + PIO_FIFO_JOIN_TX = 1, + PIO_FIFO_JOIN_RX = 2, +}; + +enum pio_mov_status_type { + STATUS_TX_LESSTHAN = 0, + STATUS_RX_LESSTHAN = 1 +}; + +enum pio_xfer_dir { + PIO_DIR_TO_SM, + PIO_DIR_FROM_SM, + PIO_DIR_COUNT +}; + +enum clock_index { + clk_sys = 5 +}; + +typedef struct pio_program { + const uint16_t *instructions; + uint8_t length; + int8_t origin; // required instruction memory origin or -1 +} pio_program_t; + +enum gpio_function { + GPIO_FUNC_FSEL0 = 0, + GPIO_FUNC_FSEL1 = 1, + GPIO_FUNC_FSEL2 = 2, + GPIO_FUNC_FSEL3 = 3, + GPIO_FUNC_FSEL4 = 4, + GPIO_FUNC_FSEL5 = 5, + GPIO_FUNC_FSEL6 = 6, + GPIO_FUNC_FSEL7 = 7, + GPIO_FUNC_FSEL8 = 8, + GPIO_FUNC_NULL = 0x1f, + + // Name a few + GPIO_FUNC_SYS_RIO = 5, + GPIO_FUNC_PROC_RIO = 6, + GPIO_FUNC_PIO = 7, +}; + +enum gpio_irq_level { + GPIO_IRQ_LEVEL_LOW = 0x1u, + GPIO_IRQ_LEVEL_HIGH = 0x2u, + GPIO_IRQ_EDGE_FALL = 0x4u, + GPIO_IRQ_EDGE_RISE = 0x8u, +}; + +enum gpio_override { + GPIO_OVERRIDE_NORMAL = 0, + GPIO_OVERRIDE_INVERT = 1, + GPIO_OVERRIDE_LOW = 2, + GPIO_OVERRIDE_HIGH = 3, +}; +enum gpio_slew_rate { + GPIO_SLEW_RATE_SLOW = 0, + GPIO_SLEW_RATE_FAST = 1 +}; + +enum gpio_drive_strength { + GPIO_DRIVE_STRENGTH_2MA = 0, + GPIO_DRIVE_STRENGTH_4MA = 1, + GPIO_DRIVE_STRENGTH_8MA = 2, + GPIO_DRIVE_STRENGTH_12MA = 3 +}; + +struct fp24_8 { + uint32_t val; +}; + +typedef rp1_pio_sm_config pio_sm_config; + +typedef struct rp1_pio_client *PIO; + +int rp1_pio_init(void); +PIO rp1_pio_open(void); +void rp1_pio_close(struct rp1_pio_client *client); +void rp1_pio_set_error(struct rp1_pio_client *client, int err); +int rp1_pio_get_error(const struct rp1_pio_client *client); +void rp1_pio_clear_error(struct rp1_pio_client *client); +int rp1_pio_sm_config_xfer(struct rp1_pio_client *client, uint sm, uint dir, + uint buf_size, uint buf_count); +int rp1_pio_sm_xfer_data(struct rp1_pio_client *client, uint sm, uint dir, + uint data_bytes, void *data, dma_addr_t dma_addr, + void (*callback)(void *param), void *param); + +int rp1_pio_can_add_program(struct rp1_pio_client *client, void *param); +int rp1_pio_add_program(struct rp1_pio_client *client, void *param); +int rp1_pio_remove_program(struct rp1_pio_client *client, void *param); +int rp1_pio_clear_instr_mem(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_claim(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_unclaim(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_is_claimed(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_init(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_set_config(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_exec(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_clear_fifos(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_set_clkdiv(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_set_pins(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_set_pindirs(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_set_enabled(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_restart(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_clkdiv_restart(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_enable_sync(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_put(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_get(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_set_dmactrl(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_fifo_state(struct rp1_pio_client *client, void *param); +int rp1_pio_sm_drain_tx(struct rp1_pio_client *client, void *param); +int rp1_pio_gpio_init(struct rp1_pio_client *client, void *param); +int rp1_pio_gpio_set_function(struct rp1_pio_client *client, void *param); +int rp1_pio_gpio_set_pulls(struct rp1_pio_client *client, void *param); +int rp1_pio_gpio_set_outover(struct rp1_pio_client *client, void *param); +int rp1_pio_gpio_set_inover(struct rp1_pio_client *client, void *param); +int rp1_pio_gpio_set_oeover(struct rp1_pio_client *client, void *param); +int rp1_pio_gpio_set_input_enabled(struct rp1_pio_client *client, void *param); +int rp1_pio_gpio_set_drive_strength(struct rp1_pio_client *client, void *param); + +static inline int pio_init(void) +{ + return rp1_pio_init(); +} + +static inline struct rp1_pio_client *pio_open(void) +{ + return rp1_pio_open(); +} + +static inline void pio_close(struct rp1_pio_client *client) +{ + rp1_pio_close(client); +} + +static inline void pio_set_error(struct rp1_pio_client *client, int err) +{ + rp1_pio_set_error(client, err); +} + +static inline int pio_get_error(const struct rp1_pio_client *client) +{ + return rp1_pio_get_error(client); +} + +static inline void pio_clear_error(struct rp1_pio_client *client) +{ + rp1_pio_clear_error(client); +} + +static inline int pio_sm_config_xfer(struct rp1_pio_client *client, uint sm, uint dir, + uint buf_size, uint buf_count) +{ + return rp1_pio_sm_config_xfer(client, sm, dir, buf_size, buf_count); +} + +static inline int pio_sm_xfer_data(struct rp1_pio_client *client, uint sm, uint dir, + uint data_bytes, void *data, dma_addr_t dma_addr, + void (*callback)(void *param), void *param) +{ + return rp1_pio_sm_xfer_data(client, sm, dir, data_bytes, data, dma_addr, callback, param); +} + +static inline struct fp24_8 make_fp24_8(uint mul, uint div) +{ + struct fp24_8 res = { .val = ((unsigned long long)mul << 8) / div }; + + return res; +} + +static inline bool pio_can_add_program(struct rp1_pio_client *client, + const pio_program_t *program) +{ + struct rp1_pio_add_program_args args; + + if (bad_params_if(client, program->length > PIO_INSTRUCTION_COUNT)) + return false; + args.origin = (program->origin == -1) ? PIO_ORIGIN_ANY : program->origin; + args.num_instrs = program->length; + + memcpy(args.instrs, program->instructions, args.num_instrs * sizeof(args.instrs[0])); + return rp1_pio_can_add_program(client, &args); +} + +static inline bool pio_can_add_program_at_offset(struct rp1_pio_client *client, + const pio_program_t *program, uint offset) +{ + struct rp1_pio_add_program_args args; + + if (bad_params_if(client, program->length > PIO_INSTRUCTION_COUNT || + offset >= PIO_INSTRUCTION_COUNT)) + return false; + args.origin = offset; + args.num_instrs = program->length; + + memcpy(args.instrs, program->instructions, args.num_instrs * sizeof(args.instrs[0])); + return !rp1_pio_can_add_program(client, &args); +} + +static inline uint pio_add_program(struct rp1_pio_client *client, const pio_program_t *program) +{ + struct rp1_pio_add_program_args args; + int offset; + + if (bad_params_if(client, program->length > PIO_INSTRUCTION_COUNT)) + return PIO_ORIGIN_ANY; + args.origin = (program->origin == -1) ? PIO_ORIGIN_ANY : program->origin; + args.num_instrs = program->length; + + memcpy(args.instrs, program->instructions, args.num_instrs * sizeof(args.instrs[0])); + offset = rp1_pio_add_program(client, &args); + return (offset >= 0) ? offset : PIO_ORIGIN_ANY; +} + +static inline int pio_add_program_at_offset(struct rp1_pio_client *client, + const pio_program_t *program, uint offset) +{ + struct rp1_pio_add_program_args args; + + if (bad_params_if(client, program->length > PIO_INSTRUCTION_COUNT || + offset >= PIO_INSTRUCTION_COUNT)) + return -EINVAL; + args.origin = offset; + args.num_instrs = program->length; + + memcpy(args.instrs, program->instructions, args.num_instrs * sizeof(args.instrs[0])); + return rp1_pio_add_program(client, &args); +} + +static inline int pio_remove_program(struct rp1_pio_client *client, const pio_program_t *program, + uint loaded_offset) +{ + struct rp1_pio_remove_program_args args; + + args.origin = loaded_offset; + args.num_instrs = program->length; + + return rp1_pio_remove_program(client, &args); +} + +static inline int pio_clear_instruction_memory(struct rp1_pio_client *client) +{ + return rp1_pio_clear_instr_mem(client, NULL); +} + +static inline int pio_sm_claim(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_claim_args args = { .mask = 1 << sm }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + + return rp1_pio_sm_claim(client, &args); +} + +static inline int pio_claim_sm_mask(struct rp1_pio_client *client, uint mask) +{ + struct rp1_pio_sm_claim_args args = { .mask = mask }; + + if (bad_params_if(client, mask >= (1 << NUM_PIO_STATE_MACHINES))) + return -EINVAL; + + return rp1_pio_sm_claim(client, &args); +} + +static inline int pio_sm_unclaim(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_claim_args args = { .mask = 1 << sm }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + + return rp1_pio_sm_unclaim(client, &args); +} + +static inline int pio_claim_unused_sm(struct rp1_pio_client *client, bool required) +{ + struct rp1_pio_sm_claim_args args = { .mask = 0 }; + int sm; + + sm = rp1_pio_sm_claim(client, &args); + if (sm < 0 && required) + WARN_ON("No PIO state machines are available"); + return sm; +} + +static inline bool pio_sm_is_claimed(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_claim_args args = { .mask = (1 << sm) }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return true; + return rp1_pio_sm_is_claimed(client, &args); +} + +static inline int pio_sm_init(struct rp1_pio_client *client, uint sm, uint initial_pc, + const pio_sm_config *config) +{ + struct rp1_pio_sm_init_args args = { .sm = sm, .initial_pc = initial_pc, + .config = *config }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES || + initial_pc >= PIO_INSTRUCTION_COUNT)) + return -EINVAL; + + return rp1_pio_sm_init(client, &args); +} + +static inline int pio_sm_set_config(struct rp1_pio_client *client, uint sm, + const pio_sm_config *config) +{ + struct rp1_pio_sm_init_args args = { .sm = sm, .config = *config }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + + return rp1_pio_sm_set_config(client, &args); +} + +static inline int pio_sm_exec(struct rp1_pio_client *client, uint sm, uint instr) +{ + struct rp1_pio_sm_exec_args args = { .sm = sm, .instr = instr, .blocking = false }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES || instr > (uint16_t)~0)) + return -EINVAL; + + return rp1_pio_sm_exec(client, &args); +} + +static inline int pio_sm_exec_wait_blocking(struct rp1_pio_client *client, uint sm, uint instr) +{ + struct rp1_pio_sm_exec_args args = { .sm = sm, .instr = instr, .blocking = true }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES || instr > (uint16_t)~0)) + return -EINVAL; + + return rp1_pio_sm_exec(client, &args); +} + +static inline int pio_sm_clear_fifos(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_clear_fifos_args args = { .sm = sm }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + return rp1_pio_sm_clear_fifos(client, &args); +} + +static inline bool pio_calculate_clkdiv_from_fp24_8(struct fp24_8 div, uint16_t *div_int, + uint8_t *div_frac) +{ + uint inum = (div.val >> 8); + + if (bad_params_if(NULL, inum < 1 || inum > 65536)) + return false; + *div_int = (uint16_t)inum; + if (*div_int == 0) + *div_frac = 0; + else + *div_frac = div.val & 0xff; + return true; +} + +static inline int pio_sm_set_clkdiv_int_frac(struct rp1_pio_client *client, uint sm, + uint16_t div_int, uint8_t div_frac) +{ + struct rp1_pio_sm_set_clkdiv_args args = { .sm = sm, .div_int = div_int, + .div_frac = div_frac }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES || + (div_int == 0 && div_frac != 0))) + return -EINVAL; + return rp1_pio_sm_set_clkdiv(client, &args); +} + +static inline int pio_sm_set_clkdiv(struct rp1_pio_client *client, uint sm, struct fp24_8 div) +{ + struct rp1_pio_sm_set_clkdiv_args args = { .sm = sm }; + + if (!pio_calculate_clkdiv_from_fp24_8(div, &args.div_int, &args.div_frac)) + return -EINVAL; + return rp1_pio_sm_set_clkdiv(client, &args); +} + +static inline int pio_sm_set_pins(struct rp1_pio_client *client, uint sm, uint32_t pin_values) +{ + struct rp1_pio_sm_set_pins_args args = { .sm = sm, .values = pin_values, + .mask = GPIOS_MASK }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + return rp1_pio_sm_set_pins(client, &args); +} + +static inline int pio_sm_set_pins_with_mask(struct rp1_pio_client *client, uint sm, + uint32_t pin_values, uint32_t pin_mask) +{ + struct rp1_pio_sm_set_pins_args args = { .sm = sm, .values = pin_values, + .mask = pin_mask }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + return rp1_pio_sm_set_pins(client, &args); +} + +static inline int pio_sm_set_pindirs_with_mask(struct rp1_pio_client *client, uint sm, + uint32_t pin_dirs, uint32_t pin_mask) +{ + struct rp1_pio_sm_set_pindirs_args args = { .sm = sm, .dirs = pin_dirs, + .mask = pin_mask }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES || + (pin_dirs & GPIOS_MASK) != pin_dirs || + (pin_mask & pin_mask) != pin_mask)) + return -EINVAL; + return rp1_pio_sm_set_pindirs(client, &args); +} + +static inline int pio_sm_set_consecutive_pindirs(struct rp1_pio_client *client, uint sm, + uint pin_base, uint pin_count, bool is_out) +{ + uint32_t mask = ((1 << pin_count) - 1) << pin_base; + struct rp1_pio_sm_set_pindirs_args args = { .sm = sm, .dirs = is_out ? mask : 0, + .mask = mask }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES || + pin_base >= RP1_PIO_GPIO_COUNT || + pin_count > RP1_PIO_GPIO_COUNT || + (pin_base + pin_count) > RP1_PIO_GPIO_COUNT)) + return -EINVAL; + return rp1_pio_sm_set_pindirs(client, &args); +} + +static inline int pio_sm_set_enabled(struct rp1_pio_client *client, uint sm, bool enabled) +{ + struct rp1_pio_sm_set_enabled_args args = { .mask = (1 << sm), .enable = enabled }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + return rp1_pio_sm_set_enabled(client, &args); +} + +static inline int pio_set_sm_mask_enabled(struct rp1_pio_client *client, uint32_t mask, + bool enabled) +{ + struct rp1_pio_sm_set_enabled_args args = { .mask = mask, .enable = enabled }; + + if (bad_params_if(client, mask >= (1 << NUM_PIO_STATE_MACHINES))) + return -EINVAL; + return rp1_pio_sm_set_enabled(client, &args); +} + +static inline int pio_sm_restart(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_restart_args args = { .mask = (1 << sm) }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + return rp1_pio_sm_restart(client, &args); +} + +static inline int pio_restart_sm_mask(struct rp1_pio_client *client, uint32_t mask) +{ + struct rp1_pio_sm_restart_args args = { .mask = (uint16_t)mask }; + + if (bad_params_if(client, mask >= (1 << NUM_PIO_STATE_MACHINES))) + return -EINVAL; + return rp1_pio_sm_restart(client, &args); +} + +static inline int pio_sm_clkdiv_restart(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_restart_args args = { .mask = (1 << sm) }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + return rp1_pio_sm_clkdiv_restart(client, &args); +} + +static inline int pio_clkdiv_restart_sm_mask(struct rp1_pio_client *client, uint32_t mask) +{ + struct rp1_pio_sm_restart_args args = { .mask = (uint16_t)mask }; + + if (bad_params_if(client, mask >= (1 << NUM_PIO_STATE_MACHINES))) + return -EINVAL; + return rp1_pio_sm_clkdiv_restart(client, &args); +} + +static inline int pio_enable_sm_in_sync_mask(struct rp1_pio_client *client, uint32_t mask) +{ + struct rp1_pio_sm_enable_sync_args args = { .mask = (uint16_t)mask }; + + if (bad_params_if(client, mask >= (1 << NUM_PIO_STATE_MACHINES))) + return -EINVAL; + return rp1_pio_sm_enable_sync(client, &args); +} + +static inline int pio_sm_set_dmactrl(struct rp1_pio_client *client, uint sm, bool is_tx, + uint32_t ctrl) +{ + struct rp1_pio_sm_set_dmactrl_args args = { .sm = sm, .is_tx = is_tx, .ctrl = ctrl }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + return rp1_pio_sm_set_dmactrl(client, &args); +}; + +static inline int pio_sm_drain_tx_fifo(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_clear_fifos_args args = { .sm = sm }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + return rp1_pio_sm_drain_tx(client, &args); +}; + +static inline int pio_sm_put(struct rp1_pio_client *client, uint sm, uint32_t data) +{ + struct rp1_pio_sm_put_args args = { .sm = (uint16_t)sm, .blocking = false, .data = data }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + return rp1_pio_sm_put(client, &args); +} + +static inline int pio_sm_put_blocking(struct rp1_pio_client *client, uint sm, uint32_t data) +{ + struct rp1_pio_sm_put_args args = { .sm = (uint16_t)sm, .blocking = true, .data = data }; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + return rp1_pio_sm_put(client, &args); +} + +static inline uint32_t pio_sm_get(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_get_args args = { .sm = (uint16_t)sm, .blocking = false }; + + if (!bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + rp1_pio_sm_get(client, &args); + return args.data; +} + +static inline uint32_t pio_sm_get_blocking(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_get_args args = { .sm = (uint16_t)sm, .blocking = true }; + + if (!bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + rp1_pio_sm_get(client, &args); + return args.data; +} + +static inline int pio_sm_is_rx_fifo_empty(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_fifo_state_args args = { .sm = sm, .tx = false }; + int ret; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + ret = rp1_pio_sm_fifo_state(client, &args); + if (ret == sizeof(args)) + ret = args.empty; + return ret; +}; + +static inline int pio_sm_is_rx_fifo_full(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_fifo_state_args args = { .sm = sm, .tx = false }; + int ret; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + ret = rp1_pio_sm_fifo_state(client, &args); + if (ret == sizeof(args)) + ret = args.full; + return ret; +}; + +static inline int pio_sm_rx_fifo_level(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_fifo_state_args args = { .sm = sm, .tx = false }; + int ret; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + ret = rp1_pio_sm_fifo_state(client, &args); + if (ret == sizeof(args)) + ret = args.level; + return ret; +}; + +static inline int pio_sm_is_tx_fifo_empty(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_fifo_state_args args = { .sm = sm, .tx = true }; + int ret; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + ret = rp1_pio_sm_fifo_state(client, &args); + if (ret == sizeof(args)) + ret = args.empty; + return ret; +}; + +static inline int pio_sm_is_tx_fifo_full(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_fifo_state_args args = { .sm = sm, .tx = true }; + int ret; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + ret = rp1_pio_sm_fifo_state(client, &args); + if (ret == sizeof(args)) + ret = args.full; + return ret; +}; + +static inline int pio_sm_tx_fifo_level(struct rp1_pio_client *client, uint sm) +{ + struct rp1_pio_sm_fifo_state_args args = { .sm = sm, .tx = true }; + int ret; + + if (bad_params_if(client, sm >= NUM_PIO_STATE_MACHINES)) + return -EINVAL; + ret = rp1_pio_sm_fifo_state(client, &args); + if (ret == sizeof(args)) + ret = args.level; + return ret; +}; + +static inline void sm_config_set_out_pins(pio_sm_config *c, uint out_base, uint out_count) +{ + if (bad_params_if(NULL, out_base >= RP1_PIO_GPIO_COUNT || + out_count > RP1_PIO_GPIO_COUNT)) + return; + + c->pinctrl = (c->pinctrl & ~(PROC_PIO_SM0_PINCTRL_OUT_BASE_BITS | + PROC_PIO_SM0_PINCTRL_OUT_COUNT_BITS)) | + (out_base << PROC_PIO_SM0_PINCTRL_OUT_BASE_LSB) | + (out_count << PROC_PIO_SM0_PINCTRL_OUT_COUNT_LSB); +} + +static inline void sm_config_set_set_pins(pio_sm_config *c, uint set_base, uint set_count) +{ + if (bad_params_if(NULL, set_base >= RP1_PIO_GPIO_COUNT || + set_count > 5)) + return; + + c->pinctrl = (c->pinctrl & ~(PROC_PIO_SM0_PINCTRL_SET_BASE_BITS | + PROC_PIO_SM0_PINCTRL_SET_COUNT_BITS)) | + (set_base << PROC_PIO_SM0_PINCTRL_SET_BASE_LSB) | + (set_count << PROC_PIO_SM0_PINCTRL_SET_COUNT_LSB); +} + + +static inline void sm_config_set_in_pins(pio_sm_config *c, uint in_base) +{ + if (bad_params_if(NULL, in_base >= RP1_PIO_GPIO_COUNT)) + return; + + c->pinctrl = (c->pinctrl & ~PROC_PIO_SM0_PINCTRL_IN_BASE_BITS) | + (in_base << PROC_PIO_SM0_PINCTRL_IN_BASE_LSB); +} + +static inline void sm_config_set_sideset_pins(pio_sm_config *c, uint sideset_base) +{ + if (bad_params_if(NULL, sideset_base >= RP1_PIO_GPIO_COUNT)) + return; + + c->pinctrl = (c->pinctrl & ~PROC_PIO_SM0_PINCTRL_SIDESET_BASE_BITS) | + (sideset_base << PROC_PIO_SM0_PINCTRL_SIDESET_BASE_LSB); +} + +static inline void sm_config_set_sideset(pio_sm_config *c, uint bit_count, bool optional, + bool pindirs) +{ + if (bad_params_if(NULL, bit_count > 5 || + (optional && (bit_count == 0)))) + return; + c->pinctrl = (c->pinctrl & ~PROC_PIO_SM0_PINCTRL_SIDESET_COUNT_BITS) | + (bit_count << PROC_PIO_SM0_PINCTRL_SIDESET_COUNT_LSB); + + c->execctrl = (c->execctrl & ~(PROC_PIO_SM0_EXECCTRL_SIDE_EN_BITS | + PROC_PIO_SM0_EXECCTRL_SIDE_PINDIR_BITS)) | + (optional << PROC_PIO_SM0_EXECCTRL_SIDE_EN_LSB) | + (pindirs << PROC_PIO_SM0_EXECCTRL_SIDE_PINDIR_LSB); +} + +static inline void sm_config_set_clkdiv_int_frac(pio_sm_config *c, uint16_t div_int, + uint8_t div_frac) +{ + if (bad_params_if(NULL, div_int == 0 && div_frac != 0)) + return; + + c->clkdiv = + (((uint)div_frac) << PROC_PIO_SM0_CLKDIV_FRAC_LSB) | + (((uint)div_int) << PROC_PIO_SM0_CLKDIV_INT_LSB); +} + +static inline void sm_config_set_clkdiv(pio_sm_config *c, struct fp24_8 div) +{ + uint16_t div_int; + uint8_t div_frac; + + pio_calculate_clkdiv_from_fp24_8(div, &div_int, &div_frac); + sm_config_set_clkdiv_int_frac(c, div_int, div_frac); +} + +static inline void sm_config_set_wrap(pio_sm_config *c, uint wrap_target, uint wrap) +{ + if (bad_params_if(NULL, wrap >= PIO_INSTRUCTION_COUNT || + wrap_target >= PIO_INSTRUCTION_COUNT)) + return; + + c->execctrl = (c->execctrl & ~(PROC_PIO_SM0_EXECCTRL_WRAP_TOP_BITS | + PROC_PIO_SM0_EXECCTRL_WRAP_BOTTOM_BITS)) | + (wrap_target << PROC_PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB) | + (wrap << PROC_PIO_SM0_EXECCTRL_WRAP_TOP_LSB); +} + +static inline void sm_config_set_jmp_pin(pio_sm_config *c, uint pin) +{ + if (bad_params_if(NULL, pin >= RP1_PIO_GPIO_COUNT)) + return; + + c->execctrl = (c->execctrl & ~PROC_PIO_SM0_EXECCTRL_JMP_PIN_BITS) | + (pin << PROC_PIO_SM0_EXECCTRL_JMP_PIN_LSB); +} + +static inline void sm_config_set_in_shift(pio_sm_config *c, bool shift_right, bool autopush, + uint push_threshold) +{ + if (bad_params_if(NULL, push_threshold > 32)) + return; + + c->shiftctrl = (c->shiftctrl & + ~(PROC_PIO_SM0_SHIFTCTRL_IN_SHIFTDIR_BITS | + PROC_PIO_SM0_SHIFTCTRL_AUTOPUSH_BITS | + PROC_PIO_SM0_SHIFTCTRL_PUSH_THRESH_BITS)) | + (shift_right << PROC_PIO_SM0_SHIFTCTRL_IN_SHIFTDIR_LSB) | + (autopush << PROC_PIO_SM0_SHIFTCTRL_AUTOPUSH_LSB) | + ((push_threshold & 0x1fu) << PROC_PIO_SM0_SHIFTCTRL_PUSH_THRESH_LSB); +} + +static inline void sm_config_set_out_shift(pio_sm_config *c, bool shift_right, bool autopull, + uint pull_threshold) +{ + if (bad_params_if(NULL, pull_threshold > 32)) + return; + + c->shiftctrl = (c->shiftctrl & + ~(PROC_PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_BITS | + PROC_PIO_SM0_SHIFTCTRL_AUTOPULL_BITS | + PROC_PIO_SM0_SHIFTCTRL_PULL_THRESH_BITS)) | + (shift_right << PROC_PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_LSB) | + (autopull << PROC_PIO_SM0_SHIFTCTRL_AUTOPULL_LSB) | + ((pull_threshold & 0x1fu) << PROC_PIO_SM0_SHIFTCTRL_PULL_THRESH_LSB); +} + +static inline void sm_config_set_fifo_join(pio_sm_config *c, enum pio_fifo_join join) +{ + if (bad_params_if(NULL, join != PIO_FIFO_JOIN_NONE && + join != PIO_FIFO_JOIN_TX && + join != PIO_FIFO_JOIN_RX)) + return; + + c->shiftctrl = (c->shiftctrl & (uint)~(PROC_PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS | + PROC_PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS)) | + (((uint)join) << PROC_PIO_SM0_SHIFTCTRL_FJOIN_TX_LSB); +} + +static inline void sm_config_set_out_special(pio_sm_config *c, bool sticky, bool has_enable_pin, + uint enable_pin_index) +{ + c->execctrl = (c->execctrl & + (uint)~(PROC_PIO_SM0_EXECCTRL_OUT_STICKY_BITS | + PROC_PIO_SM0_EXECCTRL_INLINE_OUT_EN_BITS | + PROC_PIO_SM0_EXECCTRL_OUT_EN_SEL_BITS)) | + (sticky << PROC_PIO_SM0_EXECCTRL_OUT_STICKY_LSB) | + (has_enable_pin << PROC_PIO_SM0_EXECCTRL_INLINE_OUT_EN_LSB) | + ((enable_pin_index << PROC_PIO_SM0_EXECCTRL_OUT_EN_SEL_LSB) & + PROC_PIO_SM0_EXECCTRL_OUT_EN_SEL_BITS); +} + +static inline void sm_config_set_mov_status(pio_sm_config *c, enum pio_mov_status_type status_sel, + uint status_n) +{ + if (bad_params_if(NULL, status_sel != STATUS_TX_LESSTHAN && + status_sel != STATUS_RX_LESSTHAN)) + return; + + c->execctrl = (c->execctrl + & ~(PROC_PIO_SM0_EXECCTRL_STATUS_SEL_BITS | PROC_PIO_SM0_EXECCTRL_STATUS_N_BITS)) + | ((((uint)status_sel) << PROC_PIO_SM0_EXECCTRL_STATUS_SEL_LSB) & + PROC_PIO_SM0_EXECCTRL_STATUS_SEL_BITS) + | ((status_n << PROC_PIO_SM0_EXECCTRL_STATUS_N_LSB) & + PROC_PIO_SM0_EXECCTRL_STATUS_N_BITS); +} + +static inline pio_sm_config pio_get_default_sm_config(void) +{ + pio_sm_config c = { 0 }; + + sm_config_set_clkdiv_int_frac(&c, 1, 0); + sm_config_set_wrap(&c, 0, 31); + sm_config_set_in_shift(&c, true, false, 32); + sm_config_set_out_shift(&c, true, false, 32); + return c; +} + +static inline uint32_t clock_get_hz(enum clock_index clk_index) +{ + const uint32_t MHZ = 1000000; + + if (bad_params_if(NULL, clk_index != clk_sys)) + return 0; + return 200 * MHZ; +} + +static inline int pio_gpio_set_function(struct rp1_pio_client *client, uint gpio, + enum gpio_function fn) +{ + struct rp1_gpio_set_function_args args = { .gpio = gpio, .fn = fn }; + + if (bad_params_if(client, gpio >= RP1_PIO_GPIO_COUNT)) + return -EINVAL; + return rp1_pio_gpio_set_function(client, &args); +} + +static inline int pio_gpio_init(struct rp1_pio_client *client, uint gpio) +{ + struct rp1_gpio_init_args args = { .gpio = gpio }; + int ret; + + if (bad_params_if(client, gpio >= RP1_PIO_GPIO_COUNT)) + return -EINVAL; + ret = rp1_pio_gpio_init(client, &args); + if (ret) + return ret; + return pio_gpio_set_function(client, gpio, RP1_GPIO_FUNC_PIO); +} + +static inline int pio_gpio_set_pulls(struct rp1_pio_client *client, uint gpio, bool up, bool down) +{ + struct rp1_gpio_set_pulls_args args = { .gpio = gpio, .up = up, .down = down }; + + if (bad_params_if(client, gpio >= RP1_PIO_GPIO_COUNT)) + return -EINVAL; + return rp1_pio_gpio_set_pulls(client, &args); +} + +static inline int pio_gpio_set_outover(struct rp1_pio_client *client, uint gpio, uint value) +{ + struct rp1_gpio_set_args args = { .gpio = gpio, .value = value }; + + if (bad_params_if(client, gpio >= RP1_PIO_GPIO_COUNT)) + return -EINVAL; + return rp1_pio_gpio_set_outover(client, &args); +} + +static inline int pio_gpio_set_inover(struct rp1_pio_client *client, uint gpio, uint value) +{ + struct rp1_gpio_set_args args = { .gpio = gpio, .value = value }; + + if (bad_params_if(client, gpio >= RP1_PIO_GPIO_COUNT)) + return -EINVAL; + return rp1_pio_gpio_set_inover(client, &args); +} + +static inline int pio_gpio_set_oeover(struct rp1_pio_client *client, uint gpio, uint value) +{ + struct rp1_gpio_set_args args = { .gpio = gpio, .value = value }; + + if (bad_params_if(client, gpio >= RP1_PIO_GPIO_COUNT)) + return -EINVAL; + return rp1_pio_gpio_set_oeover(client, &args); +} + +static inline int pio_gpio_set_input_enabled(struct rp1_pio_client *client, uint gpio, + bool enabled) +{ + struct rp1_gpio_set_args args = { .gpio = gpio, .value = enabled }; + + if (bad_params_if(client, gpio >= RP1_PIO_GPIO_COUNT)) + return -EINVAL; + return rp1_pio_gpio_set_input_enabled(client, &args); +} + +static inline int pio_gpio_set_drive_strength(struct rp1_pio_client *client, uint gpio, + enum gpio_drive_strength drive) +{ + struct rp1_gpio_set_args args = { .gpio = gpio, .value = drive }; + + if (bad_params_if(client, gpio >= RP1_PIO_GPIO_COUNT)) + return -EINVAL; + return rp1_pio_gpio_set_drive_strength(client, &args); +} + +static inline int pio_gpio_pull_up(struct rp1_pio_client *client, uint gpio) +{ + return pio_gpio_set_pulls(client, gpio, true, false); +} + +static inline int pio_gpio_pull_down(struct rp1_pio_client *client, uint gpio) +{ + return pio_gpio_set_pulls(client, gpio, false, true); +} + +static inline int pio_gpio_disable_pulls(struct rp1_pio_client *client, uint gpio) +{ + return pio_gpio_set_pulls(client, gpio, false, false); +} + +#endif diff --git a/include/linux/platform_data/dma-bcm2708.h b/include/linux/platform_data/dma-bcm2708.h new file mode 100644 index 000000000000..6ca874d332a8 --- /dev/null +++ b/include/linux/platform_data/dma-bcm2708.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2010 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _PLAT_BCM2708_DMA_H +#define _PLAT_BCM2708_DMA_H + +/* DMA CS Control and Status bits */ +#define BCM2708_DMA_ACTIVE BIT(0) +#define BCM2708_DMA_INT BIT(2) +#define BCM2708_DMA_ISPAUSED BIT(4) /* Pause requested or not active */ +#define BCM2708_DMA_ISHELD BIT(5) /* Is held by DREQ flow control */ +#define BCM2708_DMA_ERR BIT(8) +#define BCM2708_DMA_ABORT BIT(30) /* stop current CB, go to next, WO */ +#define BCM2708_DMA_RESET BIT(31) /* WO, self clearing */ + +/* DMA control block "info" field bits */ +#define BCM2708_DMA_INT_EN BIT(0) +#define BCM2708_DMA_TDMODE BIT(1) +#define BCM2708_DMA_WAIT_RESP BIT(3) +#define BCM2708_DMA_D_INC BIT(4) +#define BCM2708_DMA_D_WIDTH BIT(5) +#define BCM2708_DMA_D_DREQ BIT(6) +#define BCM2708_DMA_S_INC BIT(8) +#define BCM2708_DMA_S_WIDTH BIT(9) +#define BCM2708_DMA_S_DREQ BIT(10) + +#define BCM2708_DMA_BURST(x) (((x) & 0xf) << 12) +#define BCM2708_DMA_PER_MAP(x) ((x) << 16) +#define BCM2708_DMA_WAITS(x) (((x) & 0x1f) << 21) + +#define BCM2708_DMA_DREQ_EMMC 11 +#define BCM2708_DMA_DREQ_SDHOST 13 + +#define BCM2708_DMA_CS 0x00 /* Control and Status */ +#define BCM2708_DMA_ADDR 0x04 +/* the current control block appears in the following registers - read only */ +#define BCM2708_DMA_INFO 0x08 +#define BCM2708_DMA_SOURCE_AD 0x0c +#define BCM2708_DMA_DEST_AD 0x10 +#define BCM2708_DMA_NEXTCB 0x1C +#define BCM2708_DMA_DEBUG 0x20 + +#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4) + BCM2708_DMA_CS) +#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4) + BCM2708_DMA_ADDR) + +#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w)) + +/* When listing features we can ask for when allocating DMA channels give + those with higher priority smaller ordinal numbers */ +#define BCM_DMA_FEATURE_FAST_ORD 0 +#define BCM_DMA_FEATURE_BULK_ORD 1 +#define BCM_DMA_FEATURE_NORMAL_ORD 2 +#define BCM_DMA_FEATURE_LITE_ORD 3 +#define BCM_DMA_FEATURE_FAST BIT(BCM_DMA_FEATURE_FAST_ORD) +#define BCM_DMA_FEATURE_BULK BIT(BCM_DMA_FEATURE_BULK_ORD) +#define BCM_DMA_FEATURE_NORMAL BIT(BCM_DMA_FEATURE_NORMAL_ORD) +#define BCM_DMA_FEATURE_LITE BIT(BCM_DMA_FEATURE_LITE_ORD) +#define BCM_DMA_FEATURE_COUNT 4 + +struct bcm2708_dma_cb { + u32 info; + u32 src; + u32 dst; + u32 length; + u32 stride; + u32 next; + u32 pad[2]; +}; + +struct scatterlist; +struct platform_device; + +#if defined(CONFIG_DMA_BCM2708) || defined(CONFIG_DMA_BCM2708_MODULE) + +int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len); +void bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block); +void bcm_dma_wait_idle(void __iomem *dma_chan_base); +bool bcm_dma_is_busy(void __iomem *dma_chan_base); +int bcm_dma_abort(void __iomem *dma_chan_base); + +/* return channel no or -ve error */ +int bcm_dma_chan_alloc(unsigned preferred_feature_set, + void __iomem **out_dma_base, int *out_dma_irq); +int bcm_dma_chan_free(int channel); + +int bcm_dmaman_probe(struct platform_device *pdev, void __iomem *base, + u32 chans_available); +int bcm_dmaman_remove(struct platform_device *pdev); + +#else /* CONFIG_DMA_BCM2708 */ + +static inline int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, + int sg_len) +{ + return 0; +} + +static inline void bcm_dma_start(void __iomem *dma_chan_base, + dma_addr_t control_block) { } + +static inline void bcm_dma_wait_idle(void __iomem *dma_chan_base) { } + +static inline bool bcm_dma_is_busy(void __iomem *dma_chan_base) +{ + return false; +} + +static inline int bcm_dma_abort(void __iomem *dma_chan_base) +{ + return -EINVAL; +} + +static inline int bcm_dma_chan_alloc(unsigned preferred_feature_set, + void __iomem **out_dma_base, + int *out_dma_irq) +{ + return -EINVAL; +} + +static inline int bcm_dma_chan_free(int channel) +{ + return -EINVAL; +} + +static inline int bcm_dmaman_probe(struct platform_device *pdev, + void __iomem *base, u32 chans_available) +{ + return 0; +} + +static inline int bcm_dmaman_remove(struct platform_device *pdev) +{ + return 0; +} + +#endif /* CONFIG_DMA_BCM2708 || CONFIG_DMA_BCM2708_MODULE */ + +#endif /* _PLAT_BCM2708_DMA_H */ diff --git a/include/linux/rp1-firmware.h b/include/linux/rp1-firmware.h new file mode 100644 index 000000000000..19f11d6d79b1 --- /dev/null +++ b/include/linux/rp1-firmware.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 2023-2024 Raspberry Pi Ltd. + */ + +#ifndef __SOC_RP1_FIRMWARE_H__ +#define __SOC_RP1_FIRMWARE_H__ + +#include <linux/types.h> +#include <linux/of_device.h> + +#define RP1_FOURCC(s) ((uint32_t)((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | (s[3] << 0))) + +struct rp1_firmware; + +#if IS_ENABLED(CONFIG_FIRMWARE_RP1) +int rp1_firmware_message(struct rp1_firmware *fw, uint16_t op, + const void *data, unsigned int data_len, + void *resp, unsigned int resp_space); +void rp1_firmware_put(struct rp1_firmware *fw); +struct rp1_firmware *rp1_firmware_get(struct device_node *fwnode); +struct rp1_firmware *devm_rp1_firmware_get(struct device *dev, struct device_node *fwnode); +int rp1_firmware_get_feature(struct rp1_firmware *fw, uint32_t fourcc, + uint32_t *op_base, uint32_t *op_count); +#else +static inline int rp1_firmware_message(struct rp1_firmware *fw, uint16_t op, + const void *data, unsigned int data_len, + void *resp, unsigned int resp_space) +{ + return -EOPNOTSUPP; +} + +static inline void rp1_firmware_put(struct rp1_firmware *fw) { } + +static inline struct rp1_firmware *rp1_firmware_get(struct device_node *fwnode) +{ + return NULL; +} + +static inline struct rp1_firmware *devm_rp1_firmware_get(struct device *dev, + struct device_node *fwnode) +{ + return NULL; +} + +static inline int rp1_firmware_get_feature(struct rp1_firmware *fw, uint32_t fourcc, + uint32_t *op_base, uint32_t *op_count) +{ + return -EOPNOTSUPP; +} +#endif + +#endif /* __SOC_RP1_FIRMWARE_H__ */ diff --git a/include/linux/rp1_platform.h b/include/linux/rp1_platform.h new file mode 100644 index 000000000000..f805dbe1ed9b --- /dev/null +++ b/include/linux/rp1_platform.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021-2022 Raspberry Pi Ltd. + * All rights reserved. + */ + +#ifndef _RP1_PLATFORM_H +#define _RP1_PLATFORM_H + +#include <vdso/bits.h> + +#define RP1_B0_CHIP_ID 0x10001927 +#define RP1_C0_CHIP_ID 0x20001927 + +#define RP1_PLATFORM_ASIC BIT(1) +#define RP1_PLATFORM_FPGA BIT(0) + +void rp1_get_platform(u32 *chip_id, u32 *platform); + +#endif diff --git a/include/linux/usb.h b/include/linux/usb.h index e85105939af8..d5e2010c47ea 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -5,23 +5,22 @@ #include <linux/mod_devicetable.h> #include <linux/usb/ch9.h> -#define USB_MAJOR 180 -#define USB_DEVICE_MAJOR 189 - +#define USB_MAJOR 180 +#define USB_DEVICE_MAJOR 189 #ifdef __KERNEL__ -#include <linux/errno.h> /* for -ENODEV */ -#include <linux/delay.h> /* for mdelay() */ -#include <linux/interrupt.h> /* for in_interrupt() */ -#include <linux/list.h> /* for struct list_head */ -#include <linux/kref.h> /* for struct kref */ -#include <linux/device.h> /* for struct device */ -#include <linux/fs.h> /* for struct file_operations */ -#include <linux/completion.h> /* for struct completion */ -#include <linux/sched.h> /* for current && schedule_timeout */ -#include <linux/mutex.h> /* for struct mutex */ -#include <linux/pm_runtime.h> /* for runtime PM */ +#include <linux/errno.h> /* for -ENODEV */ +#include <linux/delay.h> /* for mdelay() */ +#include <linux/interrupt.h> /* for in_interrupt() */ +#include <linux/list.h> /* for struct list_head */ +#include <linux/kref.h> /* for struct kref */ +#include <linux/device.h> /* for struct device */ +#include <linux/fs.h> /* for struct file_operations */ +#include <linux/completion.h> /* for struct completion */ +#include <linux/sched.h> /* for current && schedule_timeout */ +#include <linux/mutex.h> /* for struct mutex */ +#include <linux/pm_runtime.h> /* for runtime PM */ struct usb_device; struct usb_driver; @@ -73,7 +72,7 @@ struct usb_host_endpoint { void *hcpriv; struct ep_device *ep_dev; /* For sysfs info */ - unsigned char *extra; /* Extra descriptors */ + unsigned char *extra; /* Extra descriptors */ int extralen; int enabled; int streams; @@ -81,17 +80,17 @@ struct usb_host_endpoint { /* host-side wrapper for one interface setting's parsed descriptors */ struct usb_host_interface { - struct usb_interface_descriptor desc; + struct usb_interface_descriptor desc; int extralen; - unsigned char *extra; /* Extra descriptors */ + unsigned char *extra; /* Extra descriptors */ /* array of desc.bNumEndpoints endpoints associated with this * interface setting. these will be in no particular order. */ struct usb_host_endpoint *endpoint; - char *string; /* iInterface string, if present */ + char *string; /* iInterface string, if present */ }; enum usb_interface_condition { @@ -103,72 +102,73 @@ enum usb_interface_condition { int __must_check usb_find_common_endpoints(struct usb_host_interface *alt, - struct usb_endpoint_descriptor **bulk_in, - struct usb_endpoint_descriptor **bulk_out, - struct usb_endpoint_descriptor **int_in, - struct usb_endpoint_descriptor **int_out); + struct usb_endpoint_descriptor **bulk_in, + struct usb_endpoint_descriptor **bulk_out, + struct usb_endpoint_descriptor **int_in, + struct usb_endpoint_descriptor **int_out); int __must_check usb_find_common_endpoints_reverse(struct usb_host_interface *alt, - struct usb_endpoint_descriptor **bulk_in, - struct usb_endpoint_descriptor **bulk_out, - struct usb_endpoint_descriptor **int_in, - struct usb_endpoint_descriptor **int_out); + struct usb_endpoint_descriptor **bulk_in, + struct usb_endpoint_descriptor **bulk_out, + struct usb_endpoint_descriptor **int_in, + struct usb_endpoint_descriptor **int_out); static inline int __must_check usb_find_bulk_in_endpoint(struct usb_host_interface *alt, - struct usb_endpoint_descriptor **bulk_in) + struct usb_endpoint_descriptor **bulk_in) { return usb_find_common_endpoints(alt, bulk_in, NULL, NULL, NULL); } static inline int __must_check usb_find_bulk_out_endpoint(struct usb_host_interface *alt, - struct usb_endpoint_descriptor **bulk_out) + struct usb_endpoint_descriptor **bulk_out) { return usb_find_common_endpoints(alt, NULL, bulk_out, NULL, NULL); } -static inline int __must_check -usb_find_int_in_endpoint(struct usb_host_interface *alt, - struct usb_endpoint_descriptor **int_in) +static inline int __must_check usb_find_int_in_endpoint( + struct usb_host_interface *alt, struct usb_endpoint_descriptor **int_in) { return usb_find_common_endpoints(alt, NULL, NULL, int_in, NULL); } static inline int __must_check usb_find_int_out_endpoint(struct usb_host_interface *alt, - struct usb_endpoint_descriptor **int_out) + struct usb_endpoint_descriptor **int_out) { return usb_find_common_endpoints(alt, NULL, NULL, NULL, int_out); } static inline int __must_check usb_find_last_bulk_in_endpoint(struct usb_host_interface *alt, - struct usb_endpoint_descriptor **bulk_in) + struct usb_endpoint_descriptor **bulk_in) { - return usb_find_common_endpoints_reverse(alt, bulk_in, NULL, NULL, NULL); + return usb_find_common_endpoints_reverse(alt, bulk_in, NULL, NULL, + NULL); } static inline int __must_check usb_find_last_bulk_out_endpoint(struct usb_host_interface *alt, - struct usb_endpoint_descriptor **bulk_out) + struct usb_endpoint_descriptor **bulk_out) { - return usb_find_common_endpoints_reverse(alt, NULL, bulk_out, NULL, NULL); + return usb_find_common_endpoints_reverse(alt, NULL, bulk_out, NULL, + NULL); } -static inline int __must_check -usb_find_last_int_in_endpoint(struct usb_host_interface *alt, - struct usb_endpoint_descriptor **int_in) +static inline int __must_check usb_find_last_int_in_endpoint( + struct usb_host_interface *alt, struct usb_endpoint_descriptor **int_in) { return usb_find_common_endpoints_reverse(alt, NULL, NULL, int_in, NULL); } static inline int __must_check usb_find_last_int_out_endpoint(struct usb_host_interface *alt, - struct usb_endpoint_descriptor **int_out) + struct usb_endpoint_descriptor **int_out) { - return usb_find_common_endpoints_reverse(alt, NULL, NULL, NULL, int_out); + return usb_find_common_endpoints_reverse(alt, NULL, NULL, NULL, + int_out); } enum usb_wireless_status { @@ -245,34 +245,35 @@ struct usb_interface { * stored in no particular order */ struct usb_host_interface *altsetting; - struct usb_host_interface *cur_altsetting; /* the currently + struct usb_host_interface *cur_altsetting; /* the currently * active alternate setting */ - unsigned num_altsetting; /* number of alternate settings */ + unsigned num_altsetting; /* number of alternate settings */ /* If there is an interface association descriptor then it will list * the associated interfaces */ struct usb_interface_assoc_descriptor *intf_assoc; - int minor; /* minor number this interface is + int minor; /* minor number this interface is * bound to */ - enum usb_interface_condition condition; /* state of binding */ - unsigned sysfs_files_created:1; /* the sysfs attributes exist */ - unsigned ep_devs_created:1; /* endpoint "devices" exist */ - unsigned unregistering:1; /* unregistration is in progress */ - unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */ - unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */ - unsigned needs_binding:1; /* needs delayed unbind/rebind */ - unsigned resetting_device:1; /* true: bandwidth alloc after reset */ - unsigned authorized:1; /* used for interface authorization */ + enum usb_interface_condition condition; /* state of binding */ + unsigned sysfs_files_created : 1; /* the sysfs attributes exist */ + unsigned ep_devs_created : 1; /* endpoint "devices" exist */ + unsigned unregistering : 1; /* unregistration is in progress */ + unsigned needs_remote_wakeup : 1; /* driver requires remote wakeup */ + unsigned needs_altsetting0 : 1; /* switch to altsetting 0 is pending */ + unsigned needs_binding : 1; /* needs delayed unbind/rebind */ + unsigned resetting_device : 1; /* true: bandwidth alloc after reset */ + unsigned authorized : 1; /* used for interface authorization */ enum usb_wireless_status wireless_status; struct work_struct wireless_status_work; - struct device dev; /* interface specific device info */ + struct device dev; /* interface specific device info */ struct device *usb_dev; - struct work_struct reset_ws; /* for resets in atomic context */ + struct work_struct reset_ws; /* for resets in atomic context */ }; -#define to_usb_interface(__dev) container_of_const(__dev, struct usb_interface, dev) +#define to_usb_interface(__dev) \ + container_of_const(__dev, struct usb_interface, dev) static inline void *usb_get_intfdata(struct usb_interface *intf) { @@ -299,15 +300,15 @@ struct usb_interface *usb_get_intf(struct usb_interface *intf); void usb_put_intf(struct usb_interface *intf); /* Hard limit */ -#define USB_MAXENDPOINTS 30 +#define USB_MAXENDPOINTS 30 /* this maximum is arbitrary */ -#define USB_MAXINTERFACES 32 -#define USB_MAXIADS (USB_MAXINTERFACES/2) +#define USB_MAXINTERFACES 32 +#define USB_MAXIADS (USB_MAXINTERFACES / 2) -bool usb_check_bulk_endpoints( - const struct usb_interface *intf, const u8 *ep_addrs); -bool usb_check_int_endpoints( - const struct usb_interface *intf, const u8 *ep_addrs); +bool usb_check_bulk_endpoints(const struct usb_interface *intf, + const u8 *ep_addrs); +bool usb_check_int_endpoints(const struct usb_interface *intf, + const u8 *ep_addrs); /* * USB Resume Timer: Every Host controller driver should drive the resume @@ -333,7 +334,7 @@ bool usb_check_int_endpoints( * should cope with both LPJ calibration errors and devices not following every * detail of the USB Specification. */ -#define USB_RESUME_TIMEOUT 40 /* ms */ +#define USB_RESUME_TIMEOUT 40 /* ms */ /** * struct usb_interface_cache - long-term representation of a device interface @@ -350,17 +351,17 @@ bool usb_check_int_endpoints( * providing support for the /sys/kernel/debug/usb/devices pseudo-file. */ struct usb_interface_cache { - unsigned num_altsetting; /* number of alternate settings */ - struct kref ref; /* reference counter */ + unsigned num_altsetting; /* number of alternate settings */ + struct kref ref; /* reference counter */ /* variable-length array of alternate settings for this interface, * stored in no particular order */ struct usb_host_interface altsetting[]; }; -#define ref_to_usb_interface_cache(r) \ - container_of(r, struct usb_interface_cache, ref) -#define altsetting_to_usb_interface_cache(a) \ - container_of(a, struct usb_interface_cache, altsetting[0]) +#define ref_to_usb_interface_cache(r) \ + container_of(r, struct usb_interface_cache, ref) +#define altsetting_to_usb_interface_cache(a) \ + container_of(a, struct usb_interface_cache, altsetting[0]) /** * struct usb_host_config - representation of a device's configuration @@ -402,9 +403,9 @@ struct usb_interface_cache { * all its interfaces. */ struct usb_host_config { - struct usb_config_descriptor desc; + struct usb_config_descriptor desc; - char *string; /* iConfiguration string, if present */ + char *string; /* iConfiguration string, if present */ /* List of any Interface Association Descriptors in this * configuration. */ @@ -418,27 +419,26 @@ struct usb_host_config { * active configuration */ struct usb_interface_cache *intf_cache[USB_MAXINTERFACES]; - unsigned char *extra; /* Extra descriptors */ + unsigned char *extra; /* Extra descriptors */ int extralen; }; /* USB2.0 and USB3.0 device BOS descriptor set */ struct usb_host_bos { - struct usb_bos_descriptor *desc; + struct usb_bos_descriptor *desc; - struct usb_ext_cap_descriptor *ext_cap; - struct usb_ss_cap_descriptor *ss_cap; - struct usb_ssp_cap_descriptor *ssp_cap; - struct usb_ss_container_id_descriptor *ss_id; - struct usb_ptm_cap_descriptor *ptm_cap; + struct usb_ext_cap_descriptor *ext_cap; + struct usb_ss_cap_descriptor *ss_cap; + struct usb_ssp_cap_descriptor *ssp_cap; + struct usb_ss_container_id_descriptor *ss_id; + struct usb_ptm_cap_descriptor *ptm_cap; }; -int __usb_get_extra_descriptor(char *buffer, unsigned size, - unsigned char type, void **ptr, size_t min); -#define usb_get_extra_descriptor(ifpoint, type, ptr) \ - __usb_get_extra_descriptor((ifpoint)->extra, \ - (ifpoint)->extralen, \ - type, (void **)ptr, sizeof(**(ptr))) +int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, + void **ptr, size_t min); +#define usb_get_extra_descriptor(ifpoint, type, ptr) \ + __usb_get_extra_descriptor((ifpoint)->extra, (ifpoint)->extralen, \ + type, (void **)ptr, sizeof(**(ptr))) /* ----------------------------------------------------------------------- */ @@ -446,48 +446,48 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, * Allocated per bus (tree of devices) we have: */ struct usb_bus { - struct device *controller; /* host side hardware */ - struct device *sysdev; /* as seen from firmware or bus */ - int busnum; /* Bus number (in order of reg) */ - const char *bus_name; /* stable id (PCI slot_name etc) */ - u8 uses_pio_for_control; /* + struct device *controller; /* host side hardware */ + struct device *sysdev; /* as seen from firmware or bus */ + int busnum; /* Bus number (in order of reg) */ + const char *bus_name; /* stable id (PCI slot_name etc) */ + u8 uses_pio_for_control; /* * Does the host controller use PIO * for control transfers? */ - u8 otg_port; /* 0, or number of OTG/HNP port */ - unsigned is_b_host:1; /* true during some HNP roleswitches */ - unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */ - unsigned no_stop_on_short:1; /* + u8 otg_port; /* 0, or number of OTG/HNP port */ + unsigned is_b_host : 1; /* true during some HNP roleswitches */ + unsigned b_hnp_enable : 1; /* OTG: did A-Host enable HNP? */ + unsigned no_stop_on_short : 1; /* * Quirk: some controllers don't stop * the ep queue on a short transfer * with the URB_SHORT_NOT_OK flag set. */ - unsigned no_sg_constraint:1; /* no sg constraint */ - unsigned sg_tablesize; /* 0 or largest number of sg list entries */ + unsigned no_sg_constraint : 1; /* no sg constraint */ + unsigned sg_tablesize; /* 0 or largest number of sg list entries */ - int devnum_next; /* Next open device number in + int devnum_next; /* Next open device number in * round-robin allocation */ struct mutex devnum_next_mutex; /* devnum_next mutex */ - DECLARE_BITMAP(devmap, 128); /* USB device number allocation bitmap */ - struct usb_device *root_hub; /* Root hub */ - struct usb_bus *hs_companion; /* Companion EHCI bus, if any */ + DECLARE_BITMAP(devmap, 128); /* USB device number allocation bitmap */ + struct usb_device *root_hub; /* Root hub */ + struct usb_bus *hs_companion; /* Companion EHCI bus, if any */ - int bandwidth_allocated; /* on this bus: how much of the time + int bandwidth_allocated; /* on this bus: how much of the time * reserved for periodic (intr/iso) * requests is used, on average? * Units: microseconds/frame. * Limits: Full/low speed reserve 90%, * while high speed reserves 80%. */ - int bandwidth_int_reqs; /* number of Interrupt requests */ - int bandwidth_isoc_reqs; /* number of Isoc. requests */ + int bandwidth_int_reqs; /* number of Interrupt requests */ + int bandwidth_isoc_reqs; /* number of Isoc. requests */ - unsigned resuming_ports; /* bit array: resuming root-hub ports */ + unsigned resuming_ports; /* bit array: resuming root-hub ports */ #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) - struct mon_bus *mon_bus; /* non-null when associated */ - int monitored; /* non-zero when monitored */ + struct mon_bus *mon_bus; /* non-null when associated */ + int monitored; /* non-zero when monitored */ #endif }; @@ -515,10 +515,10 @@ enum usb_port_connect_type { */ /* For the given port, prefer the old (faster) enumeration scheme. */ -#define USB_PORT_QUIRK_OLD_SCHEME BIT(0) +#define USB_PORT_QUIRK_OLD_SCHEME BIT(0) /* Decrease TRSTRCY to 10ms during device enumeration. */ -#define USB_PORT_QUIRK_FAST_ENUM BIT(1) +#define USB_PORT_QUIRK_FAST_ENUM BIT(1) /* * USB 2.0 Link Power Management (LPM) parameters. @@ -656,17 +656,17 @@ struct usb3_lpm_parameters { * usb_set_device_state(). */ struct usb_device { - int devnum; - char devpath[16]; - u32 route; - enum usb_device_state state; - enum usb_device_speed speed; - unsigned int rx_lanes; - unsigned int tx_lanes; - enum usb_ssp_rate ssp_rate; + int devnum; + char devpath[16]; + u32 route; + enum usb_device_state state; + enum usb_device_speed speed; + unsigned int rx_lanes; + unsigned int tx_lanes; + enum usb_ssp_rate ssp_rate; - struct usb_tt *tt; - int ttport; + struct usb_tt *tt; + int ttport; unsigned int toggle[2]; @@ -691,20 +691,20 @@ struct usb_device { u8 level; u8 devaddr; - unsigned can_submit:1; - unsigned persist_enabled:1; - unsigned reset_in_progress:1; - unsigned have_langid:1; - unsigned authorized:1; - unsigned authenticated:1; - unsigned lpm_capable:1; - unsigned lpm_devinit_allow:1; - unsigned usb2_hw_lpm_capable:1; - unsigned usb2_hw_lpm_besl_capable:1; - unsigned usb2_hw_lpm_enabled:1; - unsigned usb2_hw_lpm_allowed:1; - unsigned usb3_lpm_u1_enabled:1; - unsigned usb3_lpm_u2_enabled:1; + unsigned can_submit : 1; + unsigned persist_enabled : 1; + unsigned reset_in_progress : 1; + unsigned have_langid : 1; + unsigned authorized : 1; + unsigned authenticated : 1; + unsigned lpm_capable : 1; + unsigned lpm_devinit_allow : 1; + unsigned usb2_hw_lpm_capable : 1; + unsigned usb2_hw_lpm_besl_capable : 1; + unsigned usb2_hw_lpm_enabled : 1; + unsigned usb2_hw_lpm_allowed : 1; + unsigned usb3_lpm_u1_enabled : 1; + unsigned usb3_lpm_u2_enabled : 1; int string_langid; /* static strings from the device */ @@ -738,21 +738,22 @@ struct usb_device { unsigned lpm_disable_count; u16 hub_delay; - unsigned use_generic_driver:1; + unsigned use_generic_driver : 1; }; -#define to_usb_device(__dev) container_of_const(__dev, struct usb_device, dev) +#define to_usb_device(__dev) container_of_const(__dev, struct usb_device, dev) static inline struct usb_device *__intf_to_usbdev(struct usb_interface *intf) { return to_usb_device(intf->dev.parent); } -static inline const struct usb_device *__intf_to_usbdev_const(const struct usb_interface *intf) +static inline const struct usb_device * +__intf_to_usbdev_const(const struct usb_interface *intf) { return to_usb_device((const struct device *)intf->dev.parent); } -#define interface_to_usbdev(intf) \ +#define interface_to_usbdev(intf) \ _Generic((intf), \ const struct usb_interface *: __intf_to_usbdev_const, \ struct usb_interface *: __intf_to_usbdev)(intf) @@ -760,7 +761,7 @@ static inline const struct usb_device *__intf_to_usbdev_const(const struct usb_i extern struct usb_device *usb_get_dev(struct usb_device *dev); extern void usb_put_dev(struct usb_device *dev); extern struct usb_device *usb_hub_find_child(struct usb_device *hdev, - int port1); + int port1); /** * usb_hub_for_each_child - iterate over all child devices on the hub @@ -768,17 +769,20 @@ extern struct usb_device *usb_hub_find_child(struct usb_device *hdev, * @port1: portnum associated with child device * @child: child device pointer */ -#define usb_hub_for_each_child(hdev, port1, child) \ - for (port1 = 1, child = usb_hub_find_child(hdev, port1); \ - port1 <= hdev->maxchild; \ - child = usb_hub_find_child(hdev, ++port1)) \ - if (!child) continue; else +#define usb_hub_for_each_child(hdev, port1, child) \ + for (port1 = 1, child = usb_hub_find_child(hdev, port1); \ + port1 <= hdev->maxchild; \ + child = usb_hub_find_child(hdev, ++port1)) \ + if (!child) \ + continue; \ + else /* USB device locking */ -#define usb_lock_device(udev) device_lock(&(udev)->dev) -#define usb_unlock_device(udev) device_unlock(&(udev)->dev) -#define usb_lock_device_interruptible(udev) device_lock_interruptible(&(udev)->dev) -#define usb_trylock_device(udev) device_trylock(&(udev)->dev) +#define usb_lock_device(udev) device_lock(&(udev)->dev) +#define usb_unlock_device(udev) device_unlock(&(udev)->dev) +#define usb_lock_device_interruptible(udev) \ + device_lock_interruptible(&(udev)->dev) +#define usb_trylock_device(udev) device_trylock(&(udev)->dev) extern int usb_lock_device_for_reset(struct usb_device *udev, const struct usb_interface *iface); @@ -790,16 +794,24 @@ extern struct device *usb_intf_get_dma_device(struct usb_interface *intf); #ifdef CONFIG_ACPI extern int usb_acpi_set_power_state(struct usb_device *hdev, int index, - bool enable); + bool enable); extern bool usb_acpi_power_manageable(struct usb_device *hdev, int index); extern int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index); #else static inline int usb_acpi_set_power_state(struct usb_device *hdev, int index, - bool enable) { return 0; } + bool enable) +{ + return 0; +} static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index) - { return true; } -static inline int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index) - { return 0; } +{ + return true; +} +static inline int usb_acpi_port_lpm_incapable(struct usb_device *hdev, + int index) +{ + return 0; +} #endif /* USB autosuspend and autoresume */ @@ -827,22 +839,31 @@ static inline void usb_disable_autosuspend(struct usb_device *udev) { } static inline int usb_autopm_get_interface(struct usb_interface *intf) -{ return 0; } +{ + return 0; +} static inline int usb_autopm_get_interface_async(struct usb_interface *intf) -{ return 0; } +{ + return 0; +} static inline void usb_autopm_put_interface(struct usb_interface *intf) -{ } +{ +} static inline void usb_autopm_put_interface_async(struct usb_interface *intf) -{ } -static inline void usb_autopm_get_interface_no_resume( - struct usb_interface *intf) -{ } -static inline void usb_autopm_put_interface_no_suspend( - struct usb_interface *intf) -{ } +{ +} +static inline void +usb_autopm_get_interface_no_resume(struct usb_interface *intf) +{ +} +static inline void +usb_autopm_put_interface_no_suspend(struct usb_interface *intf) +{ +} static inline void usb_mark_last_busy(struct usb_device *udev) -{ } +{ +} #endif #if IS_ENABLED(CONFIG_USB_XHCI_SIDEBAND) @@ -880,7 +901,6 @@ static inline bool usb_device_no_sg_constraint(struct usb_device *udev) return udev && udev->bus && udev->bus->no_sg_constraint; } - /*-------------------------------------------------------------------------*/ /* for drivers using iso endpoints */ @@ -888,17 +908,18 @@ extern int usb_get_current_frame_number(struct usb_device *usb_dev); /* Sets up a group of bulk endpoints to support multiple stream IDs. */ extern int usb_alloc_streams(struct usb_interface *interface, - struct usb_host_endpoint **eps, unsigned int num_eps, - unsigned int num_streams, gfp_t mem_flags); + struct usb_host_endpoint **eps, + unsigned int num_eps, unsigned int num_streams, + gfp_t mem_flags); /* Reverts a group of bulk endpoints back to not using stream IDs. */ extern int usb_free_streams(struct usb_interface *interface, - struct usb_host_endpoint **eps, unsigned int num_eps, - gfp_t mem_flags); + struct usb_host_endpoint **eps, + unsigned int num_eps, gfp_t mem_flags); /* used these for multi-interface device registration */ extern int usb_driver_claim_interface(struct usb_driver *driver, - struct usb_interface *iface, void *data); + struct usb_interface *iface, void *data); /** * usb_interface_claimed - returns true iff an interface is claimed @@ -919,10 +940,10 @@ static inline int usb_interface_claimed(struct usb_interface *iface) } extern void usb_driver_release_interface(struct usb_driver *driver, - struct usb_interface *iface); + struct usb_interface *iface); int usb_set_wireless_status(struct usb_interface *iface, - enum usb_wireless_status status); + enum usb_wireless_status status); const struct usb_device_id *usb_match_id(struct usb_interface *interface, const struct usb_device_id *id); @@ -931,21 +952,20 @@ extern int usb_match_one_id(struct usb_interface *interface, extern int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void *)); extern struct usb_interface *usb_find_interface(struct usb_driver *drv, - int minor); + int minor); extern struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, - unsigned ifnum); -extern struct usb_host_interface *usb_altnum_to_altsetting( - const struct usb_interface *intf, unsigned int altnum); -extern struct usb_host_interface *usb_find_alt_setting( - struct usb_host_config *config, - unsigned int iface_num, - unsigned int alt_num); + unsigned ifnum); +extern struct usb_host_interface * +usb_altnum_to_altsetting(const struct usb_interface *intf, unsigned int altnum); +extern struct usb_host_interface * +usb_find_alt_setting(struct usb_host_config *config, unsigned int iface_num, + unsigned int alt_num); /* port claiming functions */ int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, - struct usb_dev_state *owner); + struct usb_dev_state *owner); int usb_hub_release_port(struct usb_device *hdev, unsigned port1, - struct usb_dev_state *owner); + struct usb_dev_state *owner); /** * usb_make_path - returns stable device path in the usb tree @@ -983,19 +1003,17 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) /*-------------------------------------------------------------------------*/ #define USB_DEVICE_ID_MATCH_DEVICE \ - (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT) + (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT) #define USB_DEVICE_ID_MATCH_DEV_RANGE \ - (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI) + (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI) #define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION \ - (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE) -#define USB_DEVICE_ID_MATCH_DEV_INFO \ - (USB_DEVICE_ID_MATCH_DEV_CLASS | \ - USB_DEVICE_ID_MATCH_DEV_SUBCLASS | \ - USB_DEVICE_ID_MATCH_DEV_PROTOCOL) -#define USB_DEVICE_ID_MATCH_INT_INFO \ - (USB_DEVICE_ID_MATCH_INT_CLASS | \ - USB_DEVICE_ID_MATCH_INT_SUBCLASS | \ - USB_DEVICE_ID_MATCH_INT_PROTOCOL) + (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE) +#define USB_DEVICE_ID_MATCH_DEV_INFO \ + (USB_DEVICE_ID_MATCH_DEV_CLASS | USB_DEVICE_ID_MATCH_DEV_SUBCLASS | \ + USB_DEVICE_ID_MATCH_DEV_PROTOCOL) +#define USB_DEVICE_ID_MATCH_INT_INFO \ + (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | \ + USB_DEVICE_ID_MATCH_INT_PROTOCOL) /** * USB_DEVICE - macro used to describe a specific usb device @@ -1005,9 +1023,8 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) * This macro is used to create a struct usb_device_id that matches a * specific device. */ -#define USB_DEVICE(vend, prod) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ - .idVendor = (vend), \ +#define USB_DEVICE(vend, prod) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \ .idProduct = (prod) /** * USB_DEVICE_VER - describe a specific usb device with a version range @@ -1019,11 +1036,9 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) * This macro is used to create a struct usb_device_id that matches a * specific device, with a version range. */ -#define USB_DEVICE_VER(vend, prod, lo, hi) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \ - .idVendor = (vend), \ - .idProduct = (prod), \ - .bcdDevice_lo = (lo), \ +#define USB_DEVICE_VER(vend, prod, lo, hi) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \ + .idVendor = (vend), .idProduct = (prod), .bcdDevice_lo = (lo), \ .bcdDevice_hi = (hi) /** @@ -1035,12 +1050,10 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) * This macro is used to create a struct usb_device_id that matches a * specific interface class of devices. */ -#define USB_DEVICE_INTERFACE_CLASS(vend, prod, cl) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ +#define USB_DEVICE_INTERFACE_CLASS(vend, prod, cl) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ USB_DEVICE_ID_MATCH_INT_CLASS, \ - .idVendor = (vend), \ - .idProduct = (prod), \ - .bInterfaceClass = (cl) + .idVendor = (vend), .idProduct = (prod), .bInterfaceClass = (cl) /** * USB_DEVICE_INTERFACE_PROTOCOL - describe a usb device with a specific interface protocol @@ -1051,12 +1064,10 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) * This macro is used to create a struct usb_device_id that matches a * specific interface protocol of devices. */ -#define USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ +#define USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ - .idVendor = (vend), \ - .idProduct = (prod), \ - .bInterfaceProtocol = (pr) + .idVendor = (vend), .idProduct = (prod), .bInterfaceProtocol = (pr) /** * USB_DEVICE_INTERFACE_NUMBER - describe a usb device with a specific interface number @@ -1067,12 +1078,10 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) * This macro is used to create a struct usb_device_id that matches a * specific interface number of devices. */ -#define USB_DEVICE_INTERFACE_NUMBER(vend, prod, num) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ +#define USB_DEVICE_INTERFACE_NUMBER(vend, prod, num) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ USB_DEVICE_ID_MATCH_INT_NUMBER, \ - .idVendor = (vend), \ - .idProduct = (prod), \ - .bInterfaceNumber = (num) + .idVendor = (vend), .idProduct = (prod), .bInterfaceNumber = (num) /** * USB_DEVICE_INFO - macro used to describe a class of usb devices @@ -1083,11 +1092,9 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) * This macro is used to create a struct usb_device_id that matches a * specific class of devices. */ -#define USB_DEVICE_INFO(cl, sc, pr) \ - .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, \ - .bDeviceClass = (cl), \ - .bDeviceSubClass = (sc), \ - .bDeviceProtocol = (pr) +#define USB_DEVICE_INFO(cl, sc, pr) \ + .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), \ + .bDeviceSubClass = (sc), .bDeviceProtocol = (pr) /** * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces @@ -1098,11 +1105,9 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) * This macro is used to create a struct usb_device_id that matches a * specific class of interfaces. */ -#define USB_INTERFACE_INFO(cl, sc, pr) \ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \ - .bInterfaceClass = (cl), \ - .bInterfaceSubClass = (sc), \ - .bInterfaceProtocol = (pr) +#define USB_INTERFACE_INFO(cl, sc, pr) \ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \ + .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr) /** * USB_DEVICE_AND_INTERFACE_INFO - describe a specific usb device with a class of usb interfaces @@ -1118,14 +1123,11 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) * This is especially useful when explicitly matching devices that have * vendor specific bDeviceClass values, but standards-compliant interfaces. */ -#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr) \ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ - | USB_DEVICE_ID_MATCH_DEVICE, \ - .idVendor = (vend), \ - .idProduct = (prod), \ - .bInterfaceClass = (cl), \ - .bInterfaceSubClass = (sc), \ - .bInterfaceProtocol = (pr) +#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr) \ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | \ + USB_DEVICE_ID_MATCH_DEVICE, \ + .idVendor = (vend), .idProduct = (prod), .bInterfaceClass = (cl), \ + .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr) /** * USB_VENDOR_AND_INTERFACE_INFO - describe a specific usb vendor with a class of usb interfaces @@ -1141,12 +1143,10 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) * vendor specific bDeviceClass values, but standards-compliant interfaces. */ #define USB_VENDOR_AND_INTERFACE_INFO(vend, cl, sc, pr) \ - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \ - | USB_DEVICE_ID_MATCH_VENDOR, \ - .idVendor = (vend), \ - .bInterfaceClass = (cl), \ - .bInterfaceSubClass = (sc), \ - .bInterfaceProtocol = (pr) + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | \ + USB_DEVICE_ID_MATCH_VENDOR, \ + .idVendor = (vend), .bInterfaceClass = (cl), \ + .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr) /* ----------------------------------------------------------------------- */ @@ -1163,8 +1163,8 @@ struct usb_dynid { extern ssize_t usb_store_new_id(struct usb_dynids *dynids, const struct usb_device_id *id_table, - struct device_driver *driver, - const char *buf, size_t count); + struct device_driver *driver, const char *buf, + size_t count); extern ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf); @@ -1238,16 +1238,16 @@ extern ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf); struct usb_driver { const char *name; - int (*probe) (struct usb_interface *intf, - const struct usb_device_id *id); + int (*probe)(struct usb_interface *intf, + const struct usb_device_id *id); - void (*disconnect) (struct usb_interface *intf); + void (*disconnect)(struct usb_interface *intf); - int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code, - void *buf); + int (*unlocked_ioctl)(struct usb_interface *intf, unsigned int code, + void *buf); - int (*suspend) (struct usb_interface *intf, pm_message_t message); - int (*resume) (struct usb_interface *intf); + int (*suspend)(struct usb_interface *intf, pm_message_t message); + int (*resume)(struct usb_interface *intf); int (*reset_resume)(struct usb_interface *intf); int (*pre_reset)(struct usb_interface *intf); @@ -1260,12 +1260,12 @@ struct usb_driver { struct usb_dynids dynids; struct device_driver driver; - unsigned int no_dynamic_id:1; - unsigned int supports_autosuspend:1; - unsigned int disable_hub_initiated_lpm:1; - unsigned int soft_unbind:1; + unsigned int no_dynamic_id : 1; + unsigned int supports_autosuspend : 1; + unsigned int disable_hub_initiated_lpm : 1; + unsigned int soft_unbind : 1; }; -#define to_usb_driver(d) container_of_const(d, struct usb_driver, driver) +#define to_usb_driver(d) container_of_const(d, struct usb_driver, driver) /** * struct usb_device_driver - identifies USB device driver to usbcore @@ -1301,22 +1301,23 @@ struct usb_driver { struct usb_device_driver { const char *name; - bool (*match) (struct usb_device *udev); - int (*probe) (struct usb_device *udev); - void (*disconnect) (struct usb_device *udev); + bool (*match)(struct usb_device *udev); + int (*probe)(struct usb_device *udev); + void (*disconnect)(struct usb_device *udev); - int (*suspend) (struct usb_device *udev, pm_message_t message); - int (*resume) (struct usb_device *udev, pm_message_t message); + int (*suspend)(struct usb_device *udev, pm_message_t message); + int (*resume)(struct usb_device *udev, pm_message_t message); - int (*choose_configuration) (struct usb_device *udev); + int (*choose_configuration)(struct usb_device *udev); const struct attribute_group **dev_groups; struct device_driver driver; const struct usb_device_id *id_table; - unsigned int supports_autosuspend:1; - unsigned int generic_subclass:1; + unsigned int supports_autosuspend : 1; + unsigned int generic_subclass : 1; }; -#define to_usb_device_driver(d) container_of_const(d, struct usb_device_driver, driver) +#define to_usb_device_driver(d) \ + container_of_const(d, struct usb_device_driver, driver) /** * struct usb_class_driver - identifies a USB driver that wants to use the USB major number @@ -1359,11 +1360,10 @@ extern void usb_deregister(struct usb_driver *); * use this macro once, and calling it replaces module_init() and module_exit() */ #define module_usb_driver(__usb_driver) \ - module_driver(__usb_driver, usb_register, \ - usb_deregister) + module_driver(__usb_driver, usb_register, usb_deregister) extern int usb_register_device_driver(struct usb_device_driver *, - struct module *); + struct module *); extern void usb_deregister_device_driver(struct usb_device_driver *); extern int usb_register_dev(struct usb_interface *intf, @@ -1384,32 +1384,34 @@ extern int usb_disabled(void); * * Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb(). */ -#define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ -#define URB_ISO_ASAP 0x0002 /* iso-only; use the first unexpired +#define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ +#define URB_ISO_ASAP \ + 0x0002 /* iso-only; use the first unexpired * slot in the schedule */ -#define URB_NO_TRANSFER_DMA_MAP 0x0004 /* urb->transfer_dma valid on submit */ -#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUT with short packet */ -#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt +#define URB_NO_TRANSFER_DMA_MAP 0x0004 /* urb->transfer_dma valid on submit */ +#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUT with short packet */ +#define URB_NO_INTERRUPT \ + 0x0080 /* HINT: no non-error interrupt * needed */ -#define URB_FREE_BUFFER 0x0100 /* Free transfer buffer with the URB */ +#define URB_FREE_BUFFER 0x0100 /* Free transfer buffer with the URB */ /* The following flags are used internally by usbcore and HCDs */ -#define URB_DIR_IN 0x0200 /* Transfer from device to host */ -#define URB_DIR_OUT 0 -#define URB_DIR_MASK URB_DIR_IN +#define URB_DIR_IN 0x0200 /* Transfer from device to host */ +#define URB_DIR_OUT 0 +#define URB_DIR_MASK URB_DIR_IN -#define URB_DMA_MAP_SINGLE 0x00010000 /* Non-scatter-gather mapping */ -#define URB_DMA_MAP_PAGE 0x00020000 /* HCD-unsupported S-G */ -#define URB_DMA_MAP_SG 0x00040000 /* HCD-supported S-G */ -#define URB_MAP_LOCAL 0x00080000 /* HCD-local-memory mapping */ -#define URB_SETUP_MAP_SINGLE 0x00100000 /* Setup packet DMA mapped */ -#define URB_SETUP_MAP_LOCAL 0x00200000 /* HCD-local setup packet */ -#define URB_DMA_SG_COMBINED 0x00400000 /* S-G entries were combined */ -#define URB_ALIGNED_TEMP_BUFFER 0x00800000 /* Temp buffer was alloc'd */ +#define URB_DMA_MAP_SINGLE 0x00010000 /* Non-scatter-gather mapping */ +#define URB_DMA_MAP_PAGE 0x00020000 /* HCD-unsupported S-G */ +#define URB_DMA_MAP_SG 0x00040000 /* HCD-supported S-G */ +#define URB_MAP_LOCAL 0x00080000 /* HCD-local-memory mapping */ +#define URB_SETUP_MAP_SINGLE 0x00100000 /* Setup packet DMA mapped */ +#define URB_SETUP_MAP_LOCAL 0x00200000 /* HCD-local setup packet */ +#define URB_DMA_SG_COMBINED 0x00400000 /* S-G entries were combined */ +#define URB_ALIGNED_TEMP_BUFFER 0x00800000 /* Temp buffer was alloc'd */ struct usb_iso_packet_descriptor { unsigned int offset; - unsigned int length; /* expected length */ + unsigned int length; /* expected length */ unsigned int actual_length; int status; }; @@ -1421,7 +1423,7 @@ struct usb_anchor { wait_queue_head_t wait; spinlock_t lock; atomic_t suspend_wakeups; - unsigned int poisoned:1; + unsigned int poisoned : 1; }; static inline void init_usb_anchor(struct usb_anchor *anchor) @@ -1623,16 +1625,16 @@ typedef void (*usb_complete_t)(struct urb *); */ struct urb { /* private: usb core and host controller only fields in the urb */ - struct kref kref; /* reference count of the URB */ - int unlinked; /* unlink error code */ - void *hcpriv; /* private data for host controller */ - atomic_t use_count; /* concurrent submissions counter */ - atomic_t reject; /* submissions will fail */ + struct kref kref; /* reference count of the URB */ + int unlinked; /* unlink error code */ + void *hcpriv; /* private data for host controller */ + atomic_t use_count; /* concurrent submissions counter */ + atomic_t reject; /* submissions will fail */ /* public: documented fields in the urb that can be used by drivers */ - struct list_head urb_list; /* list head for use by the urb's + struct list_head urb_list; /* list head for use by the urb's * current owner */ - struct list_head anchor_list; /* the URB may be anchored */ + struct list_head anchor_list; /* the URB may be anchored */ struct usb_anchor *anchor; struct usb_device *dev; /* (in) pointer to associated device */ struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */ @@ -1654,11 +1656,11 @@ struct urb { int number_of_packets; /* (in) number of ISO packets */ int interval; /* (modify) transfer interval * (INT/ISO) */ - int error_count; /* (return) number of ISO errors */ - void *context; /* (in) context for completion */ - usb_complete_t complete; /* (in) completion routine */ + int error_count; /* (return) number of ISO errors */ + void *context; /* (in) context for completion */ + usb_complete_t complete; /* (in) completion routine */ struct usb_iso_packet_descriptor iso_frame_desc[]; - /* (in) ISO ONLY */ + /* (in) ISO ONLY */ }; /* ----------------------------------------------------------------------- */ @@ -1688,14 +1690,11 @@ struct urb { * cache. For more information, check &struct urb. * */ -static inline void usb_fill_control_urb(struct urb *urb, - struct usb_device *dev, - unsigned int pipe, - unsigned char *setup_packet, - void *transfer_buffer, - int buffer_length, - usb_complete_t complete_fn, - void *context) +static inline void +usb_fill_control_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, + unsigned char *setup_packet, void *transfer_buffer, + int buffer_length, usb_complete_t complete_fn, + void *context) { urb->dev = dev; urb->pipe = pipe; @@ -1723,13 +1722,10 @@ static inline void usb_fill_control_urb(struct urb *urb, * Refer to usb_fill_control_urb() for a description of the requirements for * transfer_buffer. */ -static inline void usb_fill_bulk_urb(struct urb *urb, - struct usb_device *dev, - unsigned int pipe, - void *transfer_buffer, +static inline void usb_fill_bulk_urb(struct urb *urb, struct usb_device *dev, + unsigned int pipe, void *transfer_buffer, int buffer_length, - usb_complete_t complete_fn, - void *context) + usb_complete_t complete_fn, void *context) { urb->dev = dev; urb->pipe = pipe; @@ -1763,13 +1759,10 @@ static inline void usb_fill_bulk_urb(struct urb *urb, * microframes (eight per millisecond) rather than in frames (one per * millisecond). */ -static inline void usb_fill_int_urb(struct urb *urb, - struct usb_device *dev, - unsigned int pipe, - void *transfer_buffer, +static inline void usb_fill_int_urb(struct urb *urb, struct usb_device *dev, + unsigned int pipe, void *transfer_buffer, int buffer_length, - usb_complete_t complete_fn, - void *context, + usb_complete_t complete_fn, void *context, int interval) { urb->dev = dev; @@ -1815,7 +1808,7 @@ extern struct urb *usb_get_from_anchor(struct usb_anchor *anchor); extern void usb_scuttle_anchored_urbs(struct usb_anchor *anchor); extern int usb_anchor_empty(struct usb_anchor *anchor); -#define usb_unblock_urb usb_unpoison_urb +#define usb_unblock_urb usb_unpoison_urb /** * usb_urb_dir_in - check if an URB describes an IN transfer @@ -1864,13 +1857,13 @@ void usb_free_noncoherent(struct usb_device *dev, size_t size, *-------------------------------------------------------------------*/ extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, - __u8 request, __u8 requesttype, __u16 value, __u16 index, - void *data, __u16 size, int timeout); + __u8 request, __u8 requesttype, __u16 value, + __u16 index, void *data, __u16 size, int timeout); extern int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, - void *data, int len, int *actual_length, int timeout); + void *data, int len, int *actual_length, + int timeout); extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, - void *data, int len, int *actual_length, - int timeout); + void *data, int len, int *actual_length, int timeout); /* wrappers around usb_control_msg() for the most common standard requests */ int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request, @@ -1878,29 +1871,28 @@ int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request, const void *data, __u16 size, int timeout, gfp_t memflags); int usb_control_msg_recv(struct usb_device *dev, __u8 endpoint, __u8 request, - __u8 requesttype, __u16 value, __u16 index, - void *data, __u16 size, int timeout, - gfp_t memflags); + __u8 requesttype, __u16 value, __u16 index, void *data, + __u16 size, int timeout, gfp_t memflags); extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, - unsigned char descindex, void *buf, int size); -extern int usb_get_status(struct usb_device *dev, - int recip, int type, int target, void *data); + unsigned char descindex, void *buf, int size); +extern int usb_get_status(struct usb_device *dev, int recip, int type, + int target, void *data); -static inline int usb_get_std_status(struct usb_device *dev, - int recip, int target, void *data) +static inline int usb_get_std_status(struct usb_device *dev, int recip, + int target, void *data) { return usb_get_status(dev, recip, USB_STATUS_TYPE_STANDARD, target, - data); + data); } static inline int usb_get_ptm_status(struct usb_device *dev, void *data) { - return usb_get_status(dev, USB_RECIP_DEVICE, USB_STATUS_TYPE_PTM, - 0, data); + return usb_get_status(dev, USB_RECIP_DEVICE, USB_STATUS_TYPE_PTM, 0, + data); } -extern int usb_string(struct usb_device *dev, int index, - char *buf, size_t size); +extern int usb_string(struct usb_device *dev, int index, char *buf, + size_t size); extern char *usb_cache_string(struct usb_device *udev, int index); /* wrappers that also update important state inside usbcore */ @@ -1908,6 +1900,8 @@ extern int usb_clear_halt(struct usb_device *dev, int pipe); extern int usb_reset_configuration(struct usb_device *dev); extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr); +extern void usb_fixup_endpoint(struct usb_device *dev, int epaddr, + int interval); /* this request isn't really synchronous, but it belongs with the others */ extern int usb_driver_set_configuration(struct usb_device *udev, int config); @@ -1922,9 +1916,8 @@ extern int usb_set_configuration(struct usb_device *dev, int configuration); * USB identifies 5 second timeouts, maybe more in a few cases, and a few * slow devices (like some MGE Ellipse UPSes) actually push that limit. */ -#define USB_CTRL_GET_TIMEOUT 5000 -#define USB_CTRL_SET_TIMEOUT 5000 - +#define USB_CTRL_GET_TIMEOUT 5000 +#define USB_CTRL_SET_TIMEOUT 5000 /** * struct usb_sg_request - support for scatter/gather I/O @@ -1943,39 +1936,31 @@ extern int usb_set_configuration(struct usb_device *dev, int configuration); * on the endpoint. */ struct usb_sg_request { - int status; - size_t bytes; + int status; + size_t bytes; /* private: * members below are private to usbcore, * and are not provided for driver access! */ - spinlock_t lock; + spinlock_t lock; - struct usb_device *dev; - int pipe; + struct usb_device *dev; + int pipe; - int entries; - struct urb **urbs; + int entries; + struct urb **urbs; - int count; - struct completion complete; + int count; + struct completion complete; }; -int usb_sg_init( - struct usb_sg_request *io, - struct usb_device *dev, - unsigned pipe, - unsigned period, - struct scatterlist *sg, - int nents, - size_t length, - gfp_t mem_flags -); +int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, + unsigned pipe, unsigned period, struct scatterlist *sg, + int nents, size_t length, gfp_t mem_flags); void usb_sg_cancel(struct usb_sg_request *io); void usb_sg_wait(struct usb_sg_request *io); - /* ----------------------------------------------------------------------- */ /* @@ -1997,45 +1982,45 @@ void usb_sg_wait(struct usb_sg_request *io); /* NOTE: these are not the standard USB_ENDPOINT_XFER_* values!! */ /* (yet ... they're the values used by usbfs) */ -#define PIPE_ISOCHRONOUS 0 -#define PIPE_INTERRUPT 1 -#define PIPE_CONTROL 2 -#define PIPE_BULK 3 +#define PIPE_ISOCHRONOUS 0 +#define PIPE_INTERRUPT 1 +#define PIPE_CONTROL 2 +#define PIPE_BULK 3 -#define usb_pipein(pipe) ((pipe) & USB_DIR_IN) -#define usb_pipeout(pipe) (!usb_pipein(pipe)) +#define usb_pipein(pipe) ((pipe)&USB_DIR_IN) +#define usb_pipeout(pipe) (!usb_pipein(pipe)) -#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f) -#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf) +#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f) +#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf) -#define usb_pipetype(pipe) (((pipe) >> 30) & 3) -#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS) -#define usb_pipeint(pipe) (usb_pipetype((pipe)) == PIPE_INTERRUPT) -#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == PIPE_CONTROL) -#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == PIPE_BULK) +#define usb_pipetype(pipe) (((pipe) >> 30) & 3) +#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == PIPE_ISOCHRONOUS) +#define usb_pipeint(pipe) (usb_pipetype((pipe)) == PIPE_INTERRUPT) +#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == PIPE_CONTROL) +#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == PIPE_BULK) static inline unsigned int __create_pipe(struct usb_device *dev, - unsigned int endpoint) + unsigned int endpoint) { return (dev->devnum << 8) | (endpoint << 15); } /* Create various pipes... */ -#define usb_sndctrlpipe(dev, endpoint) \ +#define usb_sndctrlpipe(dev, endpoint) \ ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint)) -#define usb_rcvctrlpipe(dev, endpoint) \ +#define usb_rcvctrlpipe(dev, endpoint) \ ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN) -#define usb_sndisocpipe(dev, endpoint) \ +#define usb_sndisocpipe(dev, endpoint) \ ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint)) -#define usb_rcvisocpipe(dev, endpoint) \ +#define usb_rcvisocpipe(dev, endpoint) \ ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN) -#define usb_sndbulkpipe(dev, endpoint) \ +#define usb_sndbulkpipe(dev, endpoint) \ ((PIPE_BULK << 30) | __create_pipe(dev, endpoint)) -#define usb_rcvbulkpipe(dev, endpoint) \ +#define usb_rcvbulkpipe(dev, endpoint) \ ((PIPE_BULK << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN) -#define usb_sndintpipe(dev, endpoint) \ +#define usb_sndintpipe(dev, endpoint) \ ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint)) -#define usb_rcvintpipe(dev, endpoint) \ +#define usb_rcvintpipe(dev, endpoint) \ ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN) static inline struct usb_host_endpoint * @@ -2078,10 +2063,10 @@ static inline int usb_translate_errors(int error_code) } /* Events from the usb core */ -#define USB_DEVICE_ADD 0x0001 -#define USB_DEVICE_REMOVE 0x0002 -#define USB_BUS_ADD 0x0003 -#define USB_BUS_REMOVE 0x0004 +#define USB_DEVICE_ADD 0x0001 +#define USB_DEVICE_REMOVE 0x0002 +#define USB_BUS_ADD 0x0003 +#define USB_BUS_REMOVE 0x0004 extern void usb_register_notify(struct notifier_block *nb); extern void usb_unregister_notify(struct notifier_block *nb); @@ -2097,9 +2082,11 @@ enum usb_led_event { #ifdef CONFIG_USB_LED_TRIG extern void usb_led_activity(enum usb_led_event ev); #else -static inline void usb_led_activity(enum usb_led_event ev) {} +static inline void usb_led_activity(enum usb_led_event ev) +{ +} #endif -#endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ #endif diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index ac95e7c89df5..8fd38368cb31 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -372,6 +372,11 @@ struct hc_driver { * or bandwidth constraints. */ void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); + /* Override the endpoint-derived interval + * (if there is any cached hardware state). + */ + void (*fixup_endpoint)(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep, int interval); /* Set the hardware-chosen device address */ int (*address_device)(struct usb_hcd *, struct usb_device *udev, unsigned int timeout_ms); @@ -437,6 +442,8 @@ extern void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *, struct urb *); extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *, struct urb *); extern void usb_hcd_flush_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); +extern void usb_hcd_fixup_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep, int interval); extern void usb_hcd_disable_endpoint(struct usb_device *udev, struct usb_host_endpoint *ep); extern void usb_hcd_reset_endpoint(struct usb_device *udev, diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h index 6135d076c53d..2d9eed47cf91 100644 --- a/include/linux/usb/otg-fsm.h +++ b/include/linux/usb/otg-fsm.h @@ -289,7 +289,7 @@ static inline int otg_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer) { if (!fsm->ops->del_timer) return -EOPNOTSUPP; - fsm->ops->del_timer(fsm, timer); + fsm->ops->timer_delete(fsm, timer); return 0; } diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index e1f87fbfe554..3e71d45477a4 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -36,6 +36,8 @@ struct rpi_firmware_property_tag_header { enum rpi_firmware_property_tag { RPI_FIRMWARE_PROPERTY_END = 0, RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001, + RPI_FIRMWARE_GET_FIRMWARE_VARIANT = 0x00000002, + RPI_FIRMWARE_GET_FIRMWARE_HASH = 0x00000003, RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010, RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011, @@ -71,6 +73,7 @@ enum rpi_firmware_property_tag { RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014, RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020, RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021, + RPI_FIRMWARE_GET_EDID_BLOCK_DISPLAY = 0x00030023, RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030, RPI_FIRMWARE_GET_THROTTLED = 0x00030046, RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047, @@ -89,9 +92,14 @@ enum rpi_firmware_property_tag { RPI_FIRMWARE_GET_PERIPH_REG = 0x00030045, RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045, RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049, - RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050, + RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00038049, + RPI_FIRMWARE_SET_POE_HAT_VAL_OLD = 0x00030050, RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058, + RPI_FIRMWARE_GET_REBOOT_FLAGS = 0x00030064, + RPI_FIRMWARE_SET_REBOOT_FLAGS = 0x00038064, RPI_FIRMWARE_NOTIFY_DISPLAY_DONE = 0x00030066, + RPI_FIRMWARE_GET_SW_UART = 0x0003008a, + RPI_FIRMWARE_SET_SW_UART = 0x0003808a, /* Dispmanx TAGS */ RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001, @@ -105,9 +113,16 @@ enum rpi_firmware_property_tag { RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009, RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a, RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b, + RPI_FIRMWARE_FRAMEBUFFER_GET_LAYER = 0x0004000c, + RPI_FIRMWARE_FRAMEBUFFER_GET_TRANSFORM = 0x0004000d, + RPI_FIRMWARE_FRAMEBUFFER_GET_VSYNC = 0x0004000e, RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f, RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010, RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001, + RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID = 0x00040016, + RPI_FIRMWARE_FRAMEBUFFER_SET_DISPLAY_NUM = 0x00048013, + RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS = 0x00040013, + RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_SETTINGS = 0x00040014, RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003, RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004, RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005, @@ -116,22 +131,33 @@ enum rpi_firmware_property_tag { RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009, RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a, RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b, + RPI_FIRMWARE_FRAMEBUFFER_TEST_LAYER = 0x0004400c, + RPI_FIRMWARE_FRAMEBUFFER_TEST_TRANSFORM = 0x0004400d, RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e, RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003, RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004, RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005, RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006, RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007, + RPI_FIRMWARE_FRAMEBUFFER_SET_PITCH = 0x00048008, RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009, RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a, RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b, + RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f, RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020, RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e, + RPI_FIRMWARE_FRAMEBUFFER_SET_LAYER = 0x0004800c, + RPI_FIRMWARE_FRAMEBUFFER_SET_TRANSFORM = 0x0004800d, RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f, RPI_FIRMWARE_VCHIQ_INIT = 0x00048010, + RPI_FIRMWARE_SET_PLANE = 0x00048015, + RPI_FIRMWARE_GET_DISPLAY_TIMING = 0x00040017, + RPI_FIRMWARE_SET_TIMING = 0x00048017, + RPI_FIRMWARE_GET_DISPLAY_CFG = 0x00040018, + RPI_FIRMWARE_SET_DISPLAY_POWER = 0x00048019, RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001, RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001, }; @@ -156,6 +182,8 @@ enum rpi_firmware_clk_id { RPI_FIRMWARE_NUM_CLK_ID, }; +#define GET_DISPLAY_SETTINGS_PAYLOAD_SIZE 64 + /** * struct rpi_firmware_clk_rate_request - Firmware Request for a rate * @id: ID of the clock being queried diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h index 22acaaec7b1c..eab4c7f3d833 100644 --- a/include/uapi/linux/fb.h +++ b/include/uapi/linux/fb.h @@ -36,6 +36,12 @@ #define FBIOPUT_MODEINFO 0x4617 #define FBIOGET_DISPINFO 0x4618 #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) +/* + * HACK: use 'z' in order not to clash with any other ioctl numbers which might + * be concurrently added to the mainline kernel + */ +#define FBIOCOPYAREA _IOW('z', 0x21, struct fb_copyarea) +#define FBIODMACOPY _IOW('z', 0x22, struct fb_dmacopy) #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ #define FB_TYPE_PLANES 1 /* Non interleaved planes */ @@ -342,6 +348,12 @@ struct fb_copyarea { __u32 sy; }; +struct fb_dmacopy { + void *dst; + __u32 src; + __u32 length; +}; + struct fb_fillrect { __u32 dx; /* screen-relative */ __u32 dy; diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 9c007a106330..90f05675213e 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -231,6 +231,9 @@ /* Sunplus UART */ #define PORT_SUNPLUS 123 +/* RPi firmware UART */ +#define PORT_RPI_FW 124 + /* Generic type identifier for ports which type is not important to userspace. */ #define PORT_GENERIC (-1) diff --git a/include/uapi/misc/rp1_pio_if.h b/include/uapi/misc/rp1_pio_if.h new file mode 100644 index 000000000000..0a0d4aca11dd --- /dev/null +++ b/include/uapi/misc/rp1_pio_if.h @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: GPL-2.0 + WITH Linux-syscall-note */ +/* + * Copyright (c) 2023-24 Raspberry Pi Ltd. + * All rights reserved. + */ +#ifndef _PIO_RP1_IF_H +#define _PIO_RP1_IF_H + +#include <linux/ioctl.h> + +#define RP1_PIO_INSTRUCTION_COUNT 32 +#define RP1_PIO_SM_COUNT 4 +#define RP1_PIO_GPIO_COUNT 28 +#define RP1_GPIO_FUNC_PIO 7 + +#define RP1_PIO_ORIGIN_ANY ((uint16_t)(~0)) + +#define RP1_PIO_DIR_TO_SM 0 +#define RP1_PIO_DIR_FROM_SM 1 +#define RP1_PIO_DIR_COUNT 2 + +typedef struct { + uint32_t clkdiv; + uint32_t execctrl; + uint32_t shiftctrl; + uint32_t pinctrl; +} rp1_pio_sm_config; + +struct rp1_pio_add_program_args { + uint16_t num_instrs; + uint16_t origin; + uint16_t instrs[RP1_PIO_INSTRUCTION_COUNT]; +}; + +struct rp1_pio_remove_program_args { + uint16_t num_instrs; + uint16_t origin; +}; + +struct rp1_pio_sm_claim_args { + uint16_t mask; +}; + +struct rp1_pio_sm_init_args { + uint16_t sm; + uint16_t initial_pc; + rp1_pio_sm_config config; +}; + +struct rp1_pio_sm_set_config_args { + uint16_t sm; + uint16_t rsvd; + rp1_pio_sm_config config; +}; + +struct rp1_pio_sm_exec_args { + uint16_t sm; + uint16_t instr; + uint8_t blocking; + uint8_t rsvd; +}; + +struct rp1_pio_sm_clear_fifos_args { + uint16_t sm; +}; + +struct rp1_pio_sm_set_clkdiv_args { + uint16_t sm; + uint16_t div_int; + uint8_t div_frac; + uint8_t rsvd; +}; + +struct rp1_pio_sm_set_pins_args { + uint16_t sm; + uint16_t rsvd; + uint32_t values; + uint32_t mask; +}; + +struct rp1_pio_sm_set_pindirs_args { + uint16_t sm; + uint16_t rsvd; + uint32_t dirs; + uint32_t mask; +}; + +struct rp1_pio_sm_set_enabled_args { + uint16_t mask; + uint8_t enable; + uint8_t rsvd; +}; + +struct rp1_pio_sm_restart_args { + uint16_t mask; +}; + +struct rp1_pio_sm_clkdiv_restart_args { + uint16_t mask; +}; + +struct rp1_pio_sm_enable_sync_args { + uint16_t mask; +}; + +struct rp1_pio_sm_put_args { + uint16_t sm; + uint8_t blocking; + uint8_t rsvd; + uint32_t data; +}; + +struct rp1_pio_sm_get_args { + uint16_t sm; + uint8_t blocking; + uint8_t rsvd; + uint32_t data; /* OUT */ +}; + +struct rp1_pio_sm_set_dmactrl_args { + uint16_t sm; + uint8_t is_tx; + uint8_t rsvd; + uint32_t ctrl; +}; + +struct rp1_pio_sm_fifo_state_args { + uint16_t sm; + uint8_t tx; + uint8_t rsvd; + uint16_t level; /* OUT */ + uint8_t empty; /* OUT */ + uint8_t full; /* OUT */ +}; + +struct rp1_gpio_init_args { + uint16_t gpio; +}; + +struct rp1_gpio_set_function_args { + uint16_t gpio; + uint16_t fn; +}; + +struct rp1_gpio_set_pulls_args { + uint16_t gpio; + uint8_t up; + uint8_t down; +}; + +struct rp1_gpio_set_args { + uint16_t gpio; + uint16_t value; +}; + +struct rp1_pio_sm_config_xfer_args { + uint16_t sm; + uint16_t dir; + uint16_t buf_size; + uint16_t buf_count; +}; + +struct rp1_pio_sm_xfer_data_args { + uint16_t sm; + uint16_t dir; + uint16_t data_bytes; + void *data; +}; + +struct rp1_pio_sm_xfer_data32_args { + uint16_t sm; + uint16_t dir; + uint32_t data_bytes; + void *data; +}; + +struct rp1_access_hw_args { + uint32_t addr; + uint32_t len; + void *data; +}; + +#define PIO_IOC_MAGIC 102 + +#define PIO_IOC_SM_CONFIG_XFER _IOW(PIO_IOC_MAGIC, 0, struct rp1_pio_sm_config_xfer_args) +#define PIO_IOC_SM_XFER_DATA _IOW(PIO_IOC_MAGIC, 1, struct rp1_pio_sm_xfer_data_args) +#define PIO_IOC_SM_XFER_DATA32 _IOW(PIO_IOC_MAGIC, 2, struct rp1_pio_sm_xfer_data32_args) + +#define PIO_IOC_READ_HW _IOW(PIO_IOC_MAGIC, 8, struct rp1_access_hw_args) +#define PIO_IOC_WRITE_HW _IOW(PIO_IOC_MAGIC, 9, struct rp1_access_hw_args) + +#define PIO_IOC_CAN_ADD_PROGRAM _IOW(PIO_IOC_MAGIC, 10, struct rp1_pio_add_program_args) +#define PIO_IOC_ADD_PROGRAM _IOW(PIO_IOC_MAGIC, 11, struct rp1_pio_add_program_args) +#define PIO_IOC_REMOVE_PROGRAM _IOW(PIO_IOC_MAGIC, 12, struct rp1_pio_remove_program_args) +#define PIO_IOC_CLEAR_INSTR_MEM _IO(PIO_IOC_MAGIC, 13) + +#define PIO_IOC_SM_CLAIM _IOW(PIO_IOC_MAGIC, 20, struct rp1_pio_sm_claim_args) +#define PIO_IOC_SM_UNCLAIM _IOW(PIO_IOC_MAGIC, 21, struct rp1_pio_sm_claim_args) +#define PIO_IOC_SM_IS_CLAIMED _IOW(PIO_IOC_MAGIC, 22, struct rp1_pio_sm_claim_args) + +#define PIO_IOC_SM_INIT _IOW(PIO_IOC_MAGIC, 30, struct rp1_pio_sm_init_args) +#define PIO_IOC_SM_SET_CONFIG _IOW(PIO_IOC_MAGIC, 31, struct rp1_pio_sm_set_config_args) +#define PIO_IOC_SM_EXEC _IOW(PIO_IOC_MAGIC, 32, struct rp1_pio_sm_exec_args) +#define PIO_IOC_SM_CLEAR_FIFOS _IOW(PIO_IOC_MAGIC, 33, struct rp1_pio_sm_clear_fifos_args) +#define PIO_IOC_SM_SET_CLKDIV _IOW(PIO_IOC_MAGIC, 34, struct rp1_pio_sm_set_clkdiv_args) +#define PIO_IOC_SM_SET_PINS _IOW(PIO_IOC_MAGIC, 35, struct rp1_pio_sm_set_pins_args) +#define PIO_IOC_SM_SET_PINDIRS _IOW(PIO_IOC_MAGIC, 36, struct rp1_pio_sm_set_pindirs_args) +#define PIO_IOC_SM_SET_ENABLED _IOW(PIO_IOC_MAGIC, 37, struct rp1_pio_sm_set_enabled_args) +#define PIO_IOC_SM_RESTART _IOW(PIO_IOC_MAGIC, 38, struct rp1_pio_sm_restart_args) +#define PIO_IOC_SM_CLKDIV_RESTART _IOW(PIO_IOC_MAGIC, 39, struct rp1_pio_sm_restart_args) +#define PIO_IOC_SM_ENABLE_SYNC _IOW(PIO_IOC_MAGIC, 40, struct rp1_pio_sm_enable_sync_args) +#define PIO_IOC_SM_PUT _IOW(PIO_IOC_MAGIC, 41, struct rp1_pio_sm_put_args) +#define PIO_IOC_SM_GET _IOWR(PIO_IOC_MAGIC, 42, struct rp1_pio_sm_get_args) +#define PIO_IOC_SM_SET_DMACTRL _IOW(PIO_IOC_MAGIC, 43, struct rp1_pio_sm_set_dmactrl_args) +#define PIO_IOC_SM_FIFO_STATE _IOW(PIO_IOC_MAGIC, 44, struct rp1_pio_sm_fifo_state_args) +#define PIO_IOC_SM_DRAIN_TX _IOW(PIO_IOC_MAGIC, 45, struct rp1_pio_sm_clear_fifos_args) + +#define PIO_IOC_GPIO_INIT _IOW(PIO_IOC_MAGIC, 50, struct rp1_gpio_init_args) +#define PIO_IOC_GPIO_SET_FUNCTION _IOW(PIO_IOC_MAGIC, 51, struct rp1_gpio_set_function_args) +#define PIO_IOC_GPIO_SET_PULLS _IOW(PIO_IOC_MAGIC, 52, struct rp1_gpio_set_pulls_args) +#define PIO_IOC_GPIO_SET_OUTOVER _IOW(PIO_IOC_MAGIC, 53, struct rp1_gpio_set_args) +#define PIO_IOC_GPIO_SET_INOVER _IOW(PIO_IOC_MAGIC, 54, struct rp1_gpio_set_args) +#define PIO_IOC_GPIO_SET_OEOVER _IOW(PIO_IOC_MAGIC, 55, struct rp1_gpio_set_args) +#define PIO_IOC_GPIO_SET_INPUT_ENABLED _IOW(PIO_IOC_MAGIC, 56, struct rp1_gpio_set_args) +#define PIO_IOC_GPIO_SET_DRIVE_STRENGTH _IOW(PIO_IOC_MAGIC, 57, struct rp1_gpio_set_args) + +#endif |
