1eddac5afSKarthikeyan Ramasubramanian // SPDX-License-Identifier: GPL-2.0 2eddac5afSKarthikeyan Ramasubramanian // Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. 3eddac5afSKarthikeyan Ramasubramanian 4*8bc529b2SLee Jones #include <linux/acpi.h> 5eddac5afSKarthikeyan Ramasubramanian #include <linux/clk.h> 6eddac5afSKarthikeyan Ramasubramanian #include <linux/slab.h> 7eddac5afSKarthikeyan Ramasubramanian #include <linux/dma-mapping.h> 8eddac5afSKarthikeyan Ramasubramanian #include <linux/io.h> 9eddac5afSKarthikeyan Ramasubramanian #include <linux/module.h> 10eddac5afSKarthikeyan Ramasubramanian #include <linux/of.h> 11eddac5afSKarthikeyan Ramasubramanian #include <linux/of_platform.h> 12eddac5afSKarthikeyan Ramasubramanian #include <linux/pinctrl/consumer.h> 13eddac5afSKarthikeyan Ramasubramanian #include <linux/platform_device.h> 14eddac5afSKarthikeyan Ramasubramanian #include <linux/qcom-geni-se.h> 15eddac5afSKarthikeyan Ramasubramanian 16eddac5afSKarthikeyan Ramasubramanian /** 17eddac5afSKarthikeyan Ramasubramanian * DOC: Overview 18eddac5afSKarthikeyan Ramasubramanian * 19eddac5afSKarthikeyan Ramasubramanian * Generic Interface (GENI) Serial Engine (SE) Wrapper driver is introduced 20eddac5afSKarthikeyan Ramasubramanian * to manage GENI firmware based Qualcomm Universal Peripheral (QUP) Wrapper 21eddac5afSKarthikeyan Ramasubramanian * controller. QUP Wrapper is designed to support various serial bus protocols 22eddac5afSKarthikeyan Ramasubramanian * like UART, SPI, I2C, I3C, etc. 23eddac5afSKarthikeyan Ramasubramanian */ 24eddac5afSKarthikeyan Ramasubramanian 25eddac5afSKarthikeyan Ramasubramanian /** 26eddac5afSKarthikeyan Ramasubramanian * DOC: Hardware description 27eddac5afSKarthikeyan Ramasubramanian * 28eddac5afSKarthikeyan Ramasubramanian * GENI based QUP is a highly-flexible and programmable module for supporting 29eddac5afSKarthikeyan Ramasubramanian * a wide range of serial interfaces like UART, SPI, I2C, I3C, etc. A single 30eddac5afSKarthikeyan Ramasubramanian * QUP module can provide upto 8 serial interfaces, using its internal 31eddac5afSKarthikeyan Ramasubramanian * serial engines. The actual configuration is determined by the target 32eddac5afSKarthikeyan Ramasubramanian * platform configuration. The protocol supported by each interface is 33eddac5afSKarthikeyan Ramasubramanian * determined by the firmware loaded to the serial engine. Each SE consists 34eddac5afSKarthikeyan Ramasubramanian * of a DMA Engine and GENI sub modules which enable serial engines to 35eddac5afSKarthikeyan Ramasubramanian * support FIFO and DMA modes of operation. 36eddac5afSKarthikeyan Ramasubramanian * 37eddac5afSKarthikeyan Ramasubramanian * 38eddac5afSKarthikeyan Ramasubramanian * +-----------------------------------------+ 39eddac5afSKarthikeyan Ramasubramanian * |QUP Wrapper | 40eddac5afSKarthikeyan Ramasubramanian * | +----------------------------+ | 41eddac5afSKarthikeyan Ramasubramanian * --QUP & SE Clocks--> | Serial Engine N | +-IO------> 42eddac5afSKarthikeyan Ramasubramanian * | | ... | | Interface 43eddac5afSKarthikeyan Ramasubramanian * <---Clock Perf.----+ +----+-----------------------+ | | 44eddac5afSKarthikeyan Ramasubramanian * State Interface | | Serial Engine 1 | | | 45eddac5afSKarthikeyan Ramasubramanian * | | | | | 46eddac5afSKarthikeyan Ramasubramanian * | | | | | 47eddac5afSKarthikeyan Ramasubramanian * <--------AHB-------> | | | | 48eddac5afSKarthikeyan Ramasubramanian * | | +----+ | 49eddac5afSKarthikeyan Ramasubramanian * | | | | 50eddac5afSKarthikeyan Ramasubramanian * | | | | 51eddac5afSKarthikeyan Ramasubramanian * <------SE IRQ------+ +----------------------------+ | 52eddac5afSKarthikeyan Ramasubramanian * | | 53eddac5afSKarthikeyan Ramasubramanian * +-----------------------------------------+ 54eddac5afSKarthikeyan Ramasubramanian * 55eddac5afSKarthikeyan Ramasubramanian * Figure 1: GENI based QUP Wrapper 56eddac5afSKarthikeyan Ramasubramanian * 57eddac5afSKarthikeyan Ramasubramanian * The GENI submodules include primary and secondary sequencers which are 58eddac5afSKarthikeyan Ramasubramanian * used to drive TX & RX operations. On serial interfaces that operate using 59eddac5afSKarthikeyan Ramasubramanian * master-slave model, primary sequencer drives both TX & RX operations. On 60eddac5afSKarthikeyan Ramasubramanian * serial interfaces that operate using peer-to-peer model, primary sequencer 61eddac5afSKarthikeyan Ramasubramanian * drives TX operation and secondary sequencer drives RX operation. 62eddac5afSKarthikeyan Ramasubramanian */ 63eddac5afSKarthikeyan Ramasubramanian 64eddac5afSKarthikeyan Ramasubramanian /** 65eddac5afSKarthikeyan Ramasubramanian * DOC: Software description 66eddac5afSKarthikeyan Ramasubramanian * 67eddac5afSKarthikeyan Ramasubramanian * GENI SE Wrapper driver is structured into 2 parts: 68eddac5afSKarthikeyan Ramasubramanian * 69eddac5afSKarthikeyan Ramasubramanian * geni_wrapper represents QUP Wrapper controller. This part of the driver 70eddac5afSKarthikeyan Ramasubramanian * manages QUP Wrapper information such as hardware version, clock 71eddac5afSKarthikeyan Ramasubramanian * performance table that is common to all the internal serial engines. 72eddac5afSKarthikeyan Ramasubramanian * 73eddac5afSKarthikeyan Ramasubramanian * geni_se represents serial engine. This part of the driver manages serial 74eddac5afSKarthikeyan Ramasubramanian * engine information such as clocks, containing QUP Wrapper, etc. This part 75eddac5afSKarthikeyan Ramasubramanian * of driver also supports operations (eg. initialize the concerned serial 76eddac5afSKarthikeyan Ramasubramanian * engine, select between FIFO and DMA mode of operation etc.) that are 77eddac5afSKarthikeyan Ramasubramanian * common to all the serial engines and are independent of serial interfaces. 78eddac5afSKarthikeyan Ramasubramanian */ 79eddac5afSKarthikeyan Ramasubramanian 80eddac5afSKarthikeyan Ramasubramanian #define MAX_CLK_PERF_LEVEL 32 81eddac5afSKarthikeyan Ramasubramanian #define NUM_AHB_CLKS 2 82eddac5afSKarthikeyan Ramasubramanian 83eddac5afSKarthikeyan Ramasubramanian /** 84eddac5afSKarthikeyan Ramasubramanian * @struct geni_wrapper - Data structure to represent the QUP Wrapper Core 85eddac5afSKarthikeyan Ramasubramanian * @dev: Device pointer of the QUP wrapper core 86eddac5afSKarthikeyan Ramasubramanian * @base: Base address of this instance of QUP wrapper core 87eddac5afSKarthikeyan Ramasubramanian * @ahb_clks: Handle to the primary & secondary AHB clocks 88eddac5afSKarthikeyan Ramasubramanian */ 89eddac5afSKarthikeyan Ramasubramanian struct geni_wrapper { 90eddac5afSKarthikeyan Ramasubramanian struct device *dev; 91eddac5afSKarthikeyan Ramasubramanian void __iomem *base; 92eddac5afSKarthikeyan Ramasubramanian struct clk_bulk_data ahb_clks[NUM_AHB_CLKS]; 93eddac5afSKarthikeyan Ramasubramanian }; 94eddac5afSKarthikeyan Ramasubramanian 95eddac5afSKarthikeyan Ramasubramanian #define QUP_HW_VER_REG 0x4 96eddac5afSKarthikeyan Ramasubramanian 97eddac5afSKarthikeyan Ramasubramanian /* Common SE registers */ 98eddac5afSKarthikeyan Ramasubramanian #define GENI_INIT_CFG_REVISION 0x0 99eddac5afSKarthikeyan Ramasubramanian #define GENI_S_INIT_CFG_REVISION 0x4 100eddac5afSKarthikeyan Ramasubramanian #define GENI_OUTPUT_CTRL 0x24 101eddac5afSKarthikeyan Ramasubramanian #define GENI_CGC_CTRL 0x28 102eddac5afSKarthikeyan Ramasubramanian #define GENI_CLK_CTRL_RO 0x60 103eddac5afSKarthikeyan Ramasubramanian #define GENI_IF_DISABLE_RO 0x64 104eddac5afSKarthikeyan Ramasubramanian #define GENI_FW_S_REVISION_RO 0x6c 105eddac5afSKarthikeyan Ramasubramanian #define SE_GENI_BYTE_GRAN 0x254 106eddac5afSKarthikeyan Ramasubramanian #define SE_GENI_TX_PACKING_CFG0 0x260 107eddac5afSKarthikeyan Ramasubramanian #define SE_GENI_TX_PACKING_CFG1 0x264 108eddac5afSKarthikeyan Ramasubramanian #define SE_GENI_RX_PACKING_CFG0 0x284 109eddac5afSKarthikeyan Ramasubramanian #define SE_GENI_RX_PACKING_CFG1 0x288 110eddac5afSKarthikeyan Ramasubramanian #define SE_GENI_M_GP_LENGTH 0x910 111eddac5afSKarthikeyan Ramasubramanian #define SE_GENI_S_GP_LENGTH 0x914 112eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_TX_PTR_L 0xc30 113eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_TX_PTR_H 0xc34 114eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_TX_ATTR 0xc38 115eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_TX_LEN 0xc3c 116eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_TX_IRQ_EN 0xc48 117eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_TX_IRQ_EN_SET 0xc4c 118eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_TX_IRQ_EN_CLR 0xc50 119eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_TX_LEN_IN 0xc54 120eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_TX_MAX_BURST 0xc5c 121eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_RX_PTR_L 0xd30 122eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_RX_PTR_H 0xd34 123eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_RX_ATTR 0xd38 124eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_RX_LEN 0xd3c 125eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_RX_IRQ_EN 0xd48 126eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_RX_IRQ_EN_SET 0xd4c 127eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_RX_IRQ_EN_CLR 0xd50 128eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_RX_LEN_IN 0xd54 129eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_RX_MAX_BURST 0xd5c 130eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_RX_FLUSH 0xd60 131eddac5afSKarthikeyan Ramasubramanian #define SE_GSI_EVENT_EN 0xe18 132eddac5afSKarthikeyan Ramasubramanian #define SE_IRQ_EN 0xe1c 133eddac5afSKarthikeyan Ramasubramanian #define SE_DMA_GENERAL_CFG 0xe30 134eddac5afSKarthikeyan Ramasubramanian 135eddac5afSKarthikeyan Ramasubramanian /* GENI_OUTPUT_CTRL fields */ 136eddac5afSKarthikeyan Ramasubramanian #define DEFAULT_IO_OUTPUT_CTRL_MSK GENMASK(6, 0) 137eddac5afSKarthikeyan Ramasubramanian 138eddac5afSKarthikeyan Ramasubramanian /* GENI_CGC_CTRL fields */ 139eddac5afSKarthikeyan Ramasubramanian #define CFG_AHB_CLK_CGC_ON BIT(0) 140eddac5afSKarthikeyan Ramasubramanian #define CFG_AHB_WR_ACLK_CGC_ON BIT(1) 141eddac5afSKarthikeyan Ramasubramanian #define DATA_AHB_CLK_CGC_ON BIT(2) 142eddac5afSKarthikeyan Ramasubramanian #define SCLK_CGC_ON BIT(3) 143eddac5afSKarthikeyan Ramasubramanian #define TX_CLK_CGC_ON BIT(4) 144eddac5afSKarthikeyan Ramasubramanian #define RX_CLK_CGC_ON BIT(5) 145eddac5afSKarthikeyan Ramasubramanian #define EXT_CLK_CGC_ON BIT(6) 146eddac5afSKarthikeyan Ramasubramanian #define PROG_RAM_HCLK_OFF BIT(8) 147eddac5afSKarthikeyan Ramasubramanian #define PROG_RAM_SCLK_OFF BIT(9) 148eddac5afSKarthikeyan Ramasubramanian #define DEFAULT_CGC_EN GENMASK(6, 0) 149eddac5afSKarthikeyan Ramasubramanian 150eddac5afSKarthikeyan Ramasubramanian /* SE_GSI_EVENT_EN fields */ 151eddac5afSKarthikeyan Ramasubramanian #define DMA_RX_EVENT_EN BIT(0) 152eddac5afSKarthikeyan Ramasubramanian #define DMA_TX_EVENT_EN BIT(1) 153eddac5afSKarthikeyan Ramasubramanian #define GENI_M_EVENT_EN BIT(2) 154eddac5afSKarthikeyan Ramasubramanian #define GENI_S_EVENT_EN BIT(3) 155eddac5afSKarthikeyan Ramasubramanian 156eddac5afSKarthikeyan Ramasubramanian /* SE_IRQ_EN fields */ 157eddac5afSKarthikeyan Ramasubramanian #define DMA_RX_IRQ_EN BIT(0) 158eddac5afSKarthikeyan Ramasubramanian #define DMA_TX_IRQ_EN BIT(1) 159eddac5afSKarthikeyan Ramasubramanian #define GENI_M_IRQ_EN BIT(2) 160eddac5afSKarthikeyan Ramasubramanian #define GENI_S_IRQ_EN BIT(3) 161eddac5afSKarthikeyan Ramasubramanian 162eddac5afSKarthikeyan Ramasubramanian /* SE_DMA_GENERAL_CFG */ 163eddac5afSKarthikeyan Ramasubramanian #define DMA_RX_CLK_CGC_ON BIT(0) 164eddac5afSKarthikeyan Ramasubramanian #define DMA_TX_CLK_CGC_ON BIT(1) 165eddac5afSKarthikeyan Ramasubramanian #define DMA_AHB_SLV_CFG_ON BIT(2) 166eddac5afSKarthikeyan Ramasubramanian #define AHB_SEC_SLV_CLK_CGC_ON BIT(3) 167eddac5afSKarthikeyan Ramasubramanian #define DUMMY_RX_NON_BUFFERABLE BIT(4) 168eddac5afSKarthikeyan Ramasubramanian #define RX_DMA_ZERO_PADDING_EN BIT(5) 169eddac5afSKarthikeyan Ramasubramanian #define RX_DMA_IRQ_DELAY_MSK GENMASK(8, 6) 170eddac5afSKarthikeyan Ramasubramanian #define RX_DMA_IRQ_DELAY_SHFT 6 171eddac5afSKarthikeyan Ramasubramanian 172eddac5afSKarthikeyan Ramasubramanian /** 173eddac5afSKarthikeyan Ramasubramanian * geni_se_get_qup_hw_version() - Read the QUP wrapper Hardware version 174eddac5afSKarthikeyan Ramasubramanian * @se: Pointer to the corresponding serial engine. 175eddac5afSKarthikeyan Ramasubramanian * 176eddac5afSKarthikeyan Ramasubramanian * Return: Hardware Version of the wrapper. 177eddac5afSKarthikeyan Ramasubramanian */ 178eddac5afSKarthikeyan Ramasubramanian u32 geni_se_get_qup_hw_version(struct geni_se *se) 179eddac5afSKarthikeyan Ramasubramanian { 180eddac5afSKarthikeyan Ramasubramanian struct geni_wrapper *wrapper = se->wrapper; 181eddac5afSKarthikeyan Ramasubramanian 182eddac5afSKarthikeyan Ramasubramanian return readl_relaxed(wrapper->base + QUP_HW_VER_REG); 183eddac5afSKarthikeyan Ramasubramanian } 184eddac5afSKarthikeyan Ramasubramanian EXPORT_SYMBOL(geni_se_get_qup_hw_version); 185eddac5afSKarthikeyan Ramasubramanian 186eddac5afSKarthikeyan Ramasubramanian static void geni_se_io_set_mode(void __iomem *base) 187eddac5afSKarthikeyan Ramasubramanian { 188eddac5afSKarthikeyan Ramasubramanian u32 val; 189eddac5afSKarthikeyan Ramasubramanian 190eddac5afSKarthikeyan Ramasubramanian val = readl_relaxed(base + SE_IRQ_EN); 191eddac5afSKarthikeyan Ramasubramanian val |= GENI_M_IRQ_EN | GENI_S_IRQ_EN; 192eddac5afSKarthikeyan Ramasubramanian val |= DMA_TX_IRQ_EN | DMA_RX_IRQ_EN; 193eddac5afSKarthikeyan Ramasubramanian writel_relaxed(val, base + SE_IRQ_EN); 194eddac5afSKarthikeyan Ramasubramanian 195eddac5afSKarthikeyan Ramasubramanian val = readl_relaxed(base + SE_GENI_DMA_MODE_EN); 196eddac5afSKarthikeyan Ramasubramanian val &= ~GENI_DMA_MODE_EN; 197eddac5afSKarthikeyan Ramasubramanian writel_relaxed(val, base + SE_GENI_DMA_MODE_EN); 198eddac5afSKarthikeyan Ramasubramanian 199eddac5afSKarthikeyan Ramasubramanian writel_relaxed(0, base + SE_GSI_EVENT_EN); 200eddac5afSKarthikeyan Ramasubramanian } 201eddac5afSKarthikeyan Ramasubramanian 202eddac5afSKarthikeyan Ramasubramanian static void geni_se_io_init(void __iomem *base) 203eddac5afSKarthikeyan Ramasubramanian { 204eddac5afSKarthikeyan Ramasubramanian u32 val; 205eddac5afSKarthikeyan Ramasubramanian 206eddac5afSKarthikeyan Ramasubramanian val = readl_relaxed(base + GENI_CGC_CTRL); 207eddac5afSKarthikeyan Ramasubramanian val |= DEFAULT_CGC_EN; 208eddac5afSKarthikeyan Ramasubramanian writel_relaxed(val, base + GENI_CGC_CTRL); 209eddac5afSKarthikeyan Ramasubramanian 210eddac5afSKarthikeyan Ramasubramanian val = readl_relaxed(base + SE_DMA_GENERAL_CFG); 211eddac5afSKarthikeyan Ramasubramanian val |= AHB_SEC_SLV_CLK_CGC_ON | DMA_AHB_SLV_CFG_ON; 212eddac5afSKarthikeyan Ramasubramanian val |= DMA_TX_CLK_CGC_ON | DMA_RX_CLK_CGC_ON; 213eddac5afSKarthikeyan Ramasubramanian writel_relaxed(val, base + SE_DMA_GENERAL_CFG); 214eddac5afSKarthikeyan Ramasubramanian 215eddac5afSKarthikeyan Ramasubramanian writel_relaxed(DEFAULT_IO_OUTPUT_CTRL_MSK, base + GENI_OUTPUT_CTRL); 216eddac5afSKarthikeyan Ramasubramanian writel_relaxed(FORCE_DEFAULT, base + GENI_FORCE_DEFAULT_REG); 217eddac5afSKarthikeyan Ramasubramanian } 218eddac5afSKarthikeyan Ramasubramanian 219279536a5SAlok Chauhan static void geni_se_irq_clear(struct geni_se *se) 220279536a5SAlok Chauhan { 221279536a5SAlok Chauhan writel_relaxed(0, se->base + SE_GSI_EVENT_EN); 222279536a5SAlok Chauhan writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); 223279536a5SAlok Chauhan writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); 224279536a5SAlok Chauhan writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); 225279536a5SAlok Chauhan writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); 226279536a5SAlok Chauhan writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); 227279536a5SAlok Chauhan } 228279536a5SAlok Chauhan 229eddac5afSKarthikeyan Ramasubramanian /** 230eddac5afSKarthikeyan Ramasubramanian * geni_se_init() - Initialize the GENI serial engine 231eddac5afSKarthikeyan Ramasubramanian * @se: Pointer to the concerned serial engine. 232eddac5afSKarthikeyan Ramasubramanian * @rx_wm: Receive watermark, in units of FIFO words. 233eddac5afSKarthikeyan Ramasubramanian * @rx_rfr_wm: Ready-for-receive watermark, in units of FIFO words. 234eddac5afSKarthikeyan Ramasubramanian * 235eddac5afSKarthikeyan Ramasubramanian * This function is used to initialize the GENI serial engine, configure 236eddac5afSKarthikeyan Ramasubramanian * receive watermark and ready-for-receive watermarks. 237eddac5afSKarthikeyan Ramasubramanian */ 238eddac5afSKarthikeyan Ramasubramanian void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr) 239eddac5afSKarthikeyan Ramasubramanian { 240eddac5afSKarthikeyan Ramasubramanian u32 val; 241eddac5afSKarthikeyan Ramasubramanian 242279536a5SAlok Chauhan geni_se_irq_clear(se); 243eddac5afSKarthikeyan Ramasubramanian geni_se_io_init(se->base); 244eddac5afSKarthikeyan Ramasubramanian geni_se_io_set_mode(se->base); 245eddac5afSKarthikeyan Ramasubramanian 246eddac5afSKarthikeyan Ramasubramanian writel_relaxed(rx_wm, se->base + SE_GENI_RX_WATERMARK_REG); 247eddac5afSKarthikeyan Ramasubramanian writel_relaxed(rx_rfr, se->base + SE_GENI_RX_RFR_WATERMARK_REG); 248eddac5afSKarthikeyan Ramasubramanian 249eddac5afSKarthikeyan Ramasubramanian val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); 250eddac5afSKarthikeyan Ramasubramanian val |= M_COMMON_GENI_M_IRQ_EN; 251eddac5afSKarthikeyan Ramasubramanian writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN); 252eddac5afSKarthikeyan Ramasubramanian 253eddac5afSKarthikeyan Ramasubramanian val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN); 254eddac5afSKarthikeyan Ramasubramanian val |= S_COMMON_GENI_S_IRQ_EN; 255eddac5afSKarthikeyan Ramasubramanian writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN); 256eddac5afSKarthikeyan Ramasubramanian } 257eddac5afSKarthikeyan Ramasubramanian EXPORT_SYMBOL(geni_se_init); 258eddac5afSKarthikeyan Ramasubramanian 259eddac5afSKarthikeyan Ramasubramanian static void geni_se_select_fifo_mode(struct geni_se *se) 260eddac5afSKarthikeyan Ramasubramanian { 261eddac5afSKarthikeyan Ramasubramanian u32 proto = geni_se_read_proto(se); 262eddac5afSKarthikeyan Ramasubramanian u32 val; 263eddac5afSKarthikeyan Ramasubramanian 264279536a5SAlok Chauhan geni_se_irq_clear(se); 265eddac5afSKarthikeyan Ramasubramanian 266eddac5afSKarthikeyan Ramasubramanian val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); 267eddac5afSKarthikeyan Ramasubramanian if (proto != GENI_SE_UART) { 268eddac5afSKarthikeyan Ramasubramanian val |= M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN; 269eddac5afSKarthikeyan Ramasubramanian val |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; 270eddac5afSKarthikeyan Ramasubramanian } 271eddac5afSKarthikeyan Ramasubramanian writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN); 272eddac5afSKarthikeyan Ramasubramanian 273eddac5afSKarthikeyan Ramasubramanian val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN); 274eddac5afSKarthikeyan Ramasubramanian if (proto != GENI_SE_UART) 275eddac5afSKarthikeyan Ramasubramanian val |= S_CMD_DONE_EN; 276eddac5afSKarthikeyan Ramasubramanian writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN); 277eddac5afSKarthikeyan Ramasubramanian 278eddac5afSKarthikeyan Ramasubramanian val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN); 279eddac5afSKarthikeyan Ramasubramanian val &= ~GENI_DMA_MODE_EN; 280eddac5afSKarthikeyan Ramasubramanian writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN); 281eddac5afSKarthikeyan Ramasubramanian } 282eddac5afSKarthikeyan Ramasubramanian 283eddac5afSKarthikeyan Ramasubramanian static void geni_se_select_dma_mode(struct geni_se *se) 284eddac5afSKarthikeyan Ramasubramanian { 285eddac5afSKarthikeyan Ramasubramanian u32 val; 286eddac5afSKarthikeyan Ramasubramanian 287279536a5SAlok Chauhan geni_se_irq_clear(se); 288eddac5afSKarthikeyan Ramasubramanian 289eddac5afSKarthikeyan Ramasubramanian val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN); 290eddac5afSKarthikeyan Ramasubramanian val |= GENI_DMA_MODE_EN; 291eddac5afSKarthikeyan Ramasubramanian writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN); 292eddac5afSKarthikeyan Ramasubramanian } 293eddac5afSKarthikeyan Ramasubramanian 294eddac5afSKarthikeyan Ramasubramanian /** 295eddac5afSKarthikeyan Ramasubramanian * geni_se_select_mode() - Select the serial engine transfer mode 296eddac5afSKarthikeyan Ramasubramanian * @se: Pointer to the concerned serial engine. 297eddac5afSKarthikeyan Ramasubramanian * @mode: Transfer mode to be selected. 298eddac5afSKarthikeyan Ramasubramanian */ 299eddac5afSKarthikeyan Ramasubramanian void geni_se_select_mode(struct geni_se *se, enum geni_se_xfer_mode mode) 300eddac5afSKarthikeyan Ramasubramanian { 301eddac5afSKarthikeyan Ramasubramanian WARN_ON(mode != GENI_SE_FIFO && mode != GENI_SE_DMA); 302eddac5afSKarthikeyan Ramasubramanian 303eddac5afSKarthikeyan Ramasubramanian switch (mode) { 304eddac5afSKarthikeyan Ramasubramanian case GENI_SE_FIFO: 305eddac5afSKarthikeyan Ramasubramanian geni_se_select_fifo_mode(se); 306eddac5afSKarthikeyan Ramasubramanian break; 307eddac5afSKarthikeyan Ramasubramanian case GENI_SE_DMA: 308eddac5afSKarthikeyan Ramasubramanian geni_se_select_dma_mode(se); 309eddac5afSKarthikeyan Ramasubramanian break; 310eddac5afSKarthikeyan Ramasubramanian case GENI_SE_INVALID: 311eddac5afSKarthikeyan Ramasubramanian default: 312eddac5afSKarthikeyan Ramasubramanian break; 313eddac5afSKarthikeyan Ramasubramanian } 314eddac5afSKarthikeyan Ramasubramanian } 315eddac5afSKarthikeyan Ramasubramanian EXPORT_SYMBOL(geni_se_select_mode); 316eddac5afSKarthikeyan Ramasubramanian 317eddac5afSKarthikeyan Ramasubramanian /** 318eddac5afSKarthikeyan Ramasubramanian * DOC: Overview 319eddac5afSKarthikeyan Ramasubramanian * 320eddac5afSKarthikeyan Ramasubramanian * GENI FIFO packing is highly configurable. TX/RX packing/unpacking consist 321eddac5afSKarthikeyan Ramasubramanian * of up to 4 operations, each operation represented by 4 configuration vectors 322eddac5afSKarthikeyan Ramasubramanian * of 10 bits programmed in GENI_TX_PACKING_CFG0 and GENI_TX_PACKING_CFG1 for 323eddac5afSKarthikeyan Ramasubramanian * TX FIFO and in GENI_RX_PACKING_CFG0 and GENI_RX_PACKING_CFG1 for RX FIFO. 324eddac5afSKarthikeyan Ramasubramanian * Refer to below examples for detailed bit-field description. 325eddac5afSKarthikeyan Ramasubramanian * 326eddac5afSKarthikeyan Ramasubramanian * Example 1: word_size = 7, packing_mode = 4 x 8, msb_to_lsb = 1 327eddac5afSKarthikeyan Ramasubramanian * 328eddac5afSKarthikeyan Ramasubramanian * +-----------+-------+-------+-------+-------+ 329eddac5afSKarthikeyan Ramasubramanian * | | vec_0 | vec_1 | vec_2 | vec_3 | 330eddac5afSKarthikeyan Ramasubramanian * +-----------+-------+-------+-------+-------+ 331eddac5afSKarthikeyan Ramasubramanian * | start | 0x6 | 0xe | 0x16 | 0x1e | 332eddac5afSKarthikeyan Ramasubramanian * | direction | 1 | 1 | 1 | 1 | 333eddac5afSKarthikeyan Ramasubramanian * | length | 6 | 6 | 6 | 6 | 334eddac5afSKarthikeyan Ramasubramanian * | stop | 0 | 0 | 0 | 1 | 335eddac5afSKarthikeyan Ramasubramanian * +-----------+-------+-------+-------+-------+ 336eddac5afSKarthikeyan Ramasubramanian * 337eddac5afSKarthikeyan Ramasubramanian * Example 2: word_size = 15, packing_mode = 2 x 16, msb_to_lsb = 0 338eddac5afSKarthikeyan Ramasubramanian * 339eddac5afSKarthikeyan Ramasubramanian * +-----------+-------+-------+-------+-------+ 340eddac5afSKarthikeyan Ramasubramanian * | | vec_0 | vec_1 | vec_2 | vec_3 | 341eddac5afSKarthikeyan Ramasubramanian * +-----------+-------+-------+-------+-------+ 342eddac5afSKarthikeyan Ramasubramanian * | start | 0x0 | 0x8 | 0x10 | 0x18 | 343eddac5afSKarthikeyan Ramasubramanian * | direction | 0 | 0 | 0 | 0 | 344eddac5afSKarthikeyan Ramasubramanian * | length | 7 | 6 | 7 | 6 | 345eddac5afSKarthikeyan Ramasubramanian * | stop | 0 | 0 | 0 | 1 | 346eddac5afSKarthikeyan Ramasubramanian * +-----------+-------+-------+-------+-------+ 347eddac5afSKarthikeyan Ramasubramanian * 348eddac5afSKarthikeyan Ramasubramanian * Example 3: word_size = 23, packing_mode = 1 x 32, msb_to_lsb = 1 349eddac5afSKarthikeyan Ramasubramanian * 350eddac5afSKarthikeyan Ramasubramanian * +-----------+-------+-------+-------+-------+ 351eddac5afSKarthikeyan Ramasubramanian * | | vec_0 | vec_1 | vec_2 | vec_3 | 352eddac5afSKarthikeyan Ramasubramanian * +-----------+-------+-------+-------+-------+ 353eddac5afSKarthikeyan Ramasubramanian * | start | 0x16 | 0xe | 0x6 | 0x0 | 354eddac5afSKarthikeyan Ramasubramanian * | direction | 1 | 1 | 1 | 1 | 355eddac5afSKarthikeyan Ramasubramanian * | length | 7 | 7 | 6 | 0 | 356eddac5afSKarthikeyan Ramasubramanian * | stop | 0 | 0 | 1 | 0 | 357eddac5afSKarthikeyan Ramasubramanian * +-----------+-------+-------+-------+-------+ 358eddac5afSKarthikeyan Ramasubramanian * 359eddac5afSKarthikeyan Ramasubramanian */ 360eddac5afSKarthikeyan Ramasubramanian 361eddac5afSKarthikeyan Ramasubramanian #define NUM_PACKING_VECTORS 4 362eddac5afSKarthikeyan Ramasubramanian #define PACKING_START_SHIFT 5 363eddac5afSKarthikeyan Ramasubramanian #define PACKING_DIR_SHIFT 4 364eddac5afSKarthikeyan Ramasubramanian #define PACKING_LEN_SHIFT 1 365eddac5afSKarthikeyan Ramasubramanian #define PACKING_STOP_BIT BIT(0) 366eddac5afSKarthikeyan Ramasubramanian #define PACKING_VECTOR_SHIFT 10 367eddac5afSKarthikeyan Ramasubramanian /** 368eddac5afSKarthikeyan Ramasubramanian * geni_se_config_packing() - Packing configuration of the serial engine 369eddac5afSKarthikeyan Ramasubramanian * @se: Pointer to the concerned serial engine 370eddac5afSKarthikeyan Ramasubramanian * @bpw: Bits of data per transfer word. 371eddac5afSKarthikeyan Ramasubramanian * @pack_words: Number of words per fifo element. 372eddac5afSKarthikeyan Ramasubramanian * @msb_to_lsb: Transfer from MSB to LSB or vice-versa. 373eddac5afSKarthikeyan Ramasubramanian * @tx_cfg: Flag to configure the TX Packing. 374eddac5afSKarthikeyan Ramasubramanian * @rx_cfg: Flag to configure the RX Packing. 375eddac5afSKarthikeyan Ramasubramanian * 376eddac5afSKarthikeyan Ramasubramanian * This function is used to configure the packing rules for the current 377eddac5afSKarthikeyan Ramasubramanian * transfer. 378eddac5afSKarthikeyan Ramasubramanian */ 379eddac5afSKarthikeyan Ramasubramanian void geni_se_config_packing(struct geni_se *se, int bpw, int pack_words, 380eddac5afSKarthikeyan Ramasubramanian bool msb_to_lsb, bool tx_cfg, bool rx_cfg) 381eddac5afSKarthikeyan Ramasubramanian { 382eddac5afSKarthikeyan Ramasubramanian u32 cfg0, cfg1, cfg[NUM_PACKING_VECTORS] = {0}; 383eddac5afSKarthikeyan Ramasubramanian int len; 384eddac5afSKarthikeyan Ramasubramanian int temp_bpw = bpw; 385eddac5afSKarthikeyan Ramasubramanian int idx_start = msb_to_lsb ? bpw - 1 : 0; 386eddac5afSKarthikeyan Ramasubramanian int idx = idx_start; 387eddac5afSKarthikeyan Ramasubramanian int idx_delta = msb_to_lsb ? -BITS_PER_BYTE : BITS_PER_BYTE; 388eddac5afSKarthikeyan Ramasubramanian int ceil_bpw = ALIGN(bpw, BITS_PER_BYTE); 389eddac5afSKarthikeyan Ramasubramanian int iter = (ceil_bpw * pack_words) / BITS_PER_BYTE; 390eddac5afSKarthikeyan Ramasubramanian int i; 391eddac5afSKarthikeyan Ramasubramanian 392eddac5afSKarthikeyan Ramasubramanian if (iter <= 0 || iter > NUM_PACKING_VECTORS) 393eddac5afSKarthikeyan Ramasubramanian return; 394eddac5afSKarthikeyan Ramasubramanian 395eddac5afSKarthikeyan Ramasubramanian for (i = 0; i < iter; i++) { 396eddac5afSKarthikeyan Ramasubramanian len = min_t(int, temp_bpw, BITS_PER_BYTE) - 1; 397eddac5afSKarthikeyan Ramasubramanian cfg[i] = idx << PACKING_START_SHIFT; 398eddac5afSKarthikeyan Ramasubramanian cfg[i] |= msb_to_lsb << PACKING_DIR_SHIFT; 399eddac5afSKarthikeyan Ramasubramanian cfg[i] |= len << PACKING_LEN_SHIFT; 400eddac5afSKarthikeyan Ramasubramanian 401eddac5afSKarthikeyan Ramasubramanian if (temp_bpw <= BITS_PER_BYTE) { 402eddac5afSKarthikeyan Ramasubramanian idx = ((i + 1) * BITS_PER_BYTE) + idx_start; 403eddac5afSKarthikeyan Ramasubramanian temp_bpw = bpw; 404eddac5afSKarthikeyan Ramasubramanian } else { 405eddac5afSKarthikeyan Ramasubramanian idx = idx + idx_delta; 406eddac5afSKarthikeyan Ramasubramanian temp_bpw = temp_bpw - BITS_PER_BYTE; 407eddac5afSKarthikeyan Ramasubramanian } 408eddac5afSKarthikeyan Ramasubramanian } 409eddac5afSKarthikeyan Ramasubramanian cfg[iter - 1] |= PACKING_STOP_BIT; 410eddac5afSKarthikeyan Ramasubramanian cfg0 = cfg[0] | (cfg[1] << PACKING_VECTOR_SHIFT); 411eddac5afSKarthikeyan Ramasubramanian cfg1 = cfg[2] | (cfg[3] << PACKING_VECTOR_SHIFT); 412eddac5afSKarthikeyan Ramasubramanian 413eddac5afSKarthikeyan Ramasubramanian if (tx_cfg) { 414eddac5afSKarthikeyan Ramasubramanian writel_relaxed(cfg0, se->base + SE_GENI_TX_PACKING_CFG0); 415eddac5afSKarthikeyan Ramasubramanian writel_relaxed(cfg1, se->base + SE_GENI_TX_PACKING_CFG1); 416eddac5afSKarthikeyan Ramasubramanian } 417eddac5afSKarthikeyan Ramasubramanian if (rx_cfg) { 418eddac5afSKarthikeyan Ramasubramanian writel_relaxed(cfg0, se->base + SE_GENI_RX_PACKING_CFG0); 419eddac5afSKarthikeyan Ramasubramanian writel_relaxed(cfg1, se->base + SE_GENI_RX_PACKING_CFG1); 420eddac5afSKarthikeyan Ramasubramanian } 421eddac5afSKarthikeyan Ramasubramanian 422eddac5afSKarthikeyan Ramasubramanian /* 423eddac5afSKarthikeyan Ramasubramanian * Number of protocol words in each FIFO entry 424eddac5afSKarthikeyan Ramasubramanian * 0 - 4x8, four words in each entry, max word size of 8 bits 425eddac5afSKarthikeyan Ramasubramanian * 1 - 2x16, two words in each entry, max word size of 16 bits 426eddac5afSKarthikeyan Ramasubramanian * 2 - 1x32, one word in each entry, max word size of 32 bits 427eddac5afSKarthikeyan Ramasubramanian * 3 - undefined 428eddac5afSKarthikeyan Ramasubramanian */ 429eddac5afSKarthikeyan Ramasubramanian if (pack_words || bpw == 32) 430eddac5afSKarthikeyan Ramasubramanian writel_relaxed(bpw / 16, se->base + SE_GENI_BYTE_GRAN); 431eddac5afSKarthikeyan Ramasubramanian } 432eddac5afSKarthikeyan Ramasubramanian EXPORT_SYMBOL(geni_se_config_packing); 433eddac5afSKarthikeyan Ramasubramanian 434eddac5afSKarthikeyan Ramasubramanian static void geni_se_clks_off(struct geni_se *se) 435eddac5afSKarthikeyan Ramasubramanian { 436eddac5afSKarthikeyan Ramasubramanian struct geni_wrapper *wrapper = se->wrapper; 437eddac5afSKarthikeyan Ramasubramanian 438eddac5afSKarthikeyan Ramasubramanian clk_disable_unprepare(se->clk); 439eddac5afSKarthikeyan Ramasubramanian clk_bulk_disable_unprepare(ARRAY_SIZE(wrapper->ahb_clks), 440eddac5afSKarthikeyan Ramasubramanian wrapper->ahb_clks); 441eddac5afSKarthikeyan Ramasubramanian } 442eddac5afSKarthikeyan Ramasubramanian 443eddac5afSKarthikeyan Ramasubramanian /** 444eddac5afSKarthikeyan Ramasubramanian * geni_se_resources_off() - Turn off resources associated with the serial 445eddac5afSKarthikeyan Ramasubramanian * engine 446eddac5afSKarthikeyan Ramasubramanian * @se: Pointer to the concerned serial engine. 447eddac5afSKarthikeyan Ramasubramanian * 448eddac5afSKarthikeyan Ramasubramanian * Return: 0 on success, standard Linux error codes on failure/error. 449eddac5afSKarthikeyan Ramasubramanian */ 450eddac5afSKarthikeyan Ramasubramanian int geni_se_resources_off(struct geni_se *se) 451eddac5afSKarthikeyan Ramasubramanian { 452eddac5afSKarthikeyan Ramasubramanian int ret; 453eddac5afSKarthikeyan Ramasubramanian 454*8bc529b2SLee Jones if (has_acpi_companion(se->dev)) 455*8bc529b2SLee Jones return 0; 456*8bc529b2SLee Jones 457eddac5afSKarthikeyan Ramasubramanian ret = pinctrl_pm_select_sleep_state(se->dev); 458eddac5afSKarthikeyan Ramasubramanian if (ret) 459eddac5afSKarthikeyan Ramasubramanian return ret; 460eddac5afSKarthikeyan Ramasubramanian 461eddac5afSKarthikeyan Ramasubramanian geni_se_clks_off(se); 462eddac5afSKarthikeyan Ramasubramanian return 0; 463eddac5afSKarthikeyan Ramasubramanian } 464eddac5afSKarthikeyan Ramasubramanian EXPORT_SYMBOL(geni_se_resources_off); 465eddac5afSKarthikeyan Ramasubramanian 466eddac5afSKarthikeyan Ramasubramanian static int geni_se_clks_on(struct geni_se *se) 467eddac5afSKarthikeyan Ramasubramanian { 468eddac5afSKarthikeyan Ramasubramanian int ret; 469eddac5afSKarthikeyan Ramasubramanian struct geni_wrapper *wrapper = se->wrapper; 470eddac5afSKarthikeyan Ramasubramanian 471eddac5afSKarthikeyan Ramasubramanian ret = clk_bulk_prepare_enable(ARRAY_SIZE(wrapper->ahb_clks), 472eddac5afSKarthikeyan Ramasubramanian wrapper->ahb_clks); 473eddac5afSKarthikeyan Ramasubramanian if (ret) 474eddac5afSKarthikeyan Ramasubramanian return ret; 475eddac5afSKarthikeyan Ramasubramanian 476eddac5afSKarthikeyan Ramasubramanian ret = clk_prepare_enable(se->clk); 477eddac5afSKarthikeyan Ramasubramanian if (ret) 478eddac5afSKarthikeyan Ramasubramanian clk_bulk_disable_unprepare(ARRAY_SIZE(wrapper->ahb_clks), 479eddac5afSKarthikeyan Ramasubramanian wrapper->ahb_clks); 480eddac5afSKarthikeyan Ramasubramanian return ret; 481eddac5afSKarthikeyan Ramasubramanian } 482eddac5afSKarthikeyan Ramasubramanian 483eddac5afSKarthikeyan Ramasubramanian /** 484eddac5afSKarthikeyan Ramasubramanian * geni_se_resources_on() - Turn on resources associated with the serial 485eddac5afSKarthikeyan Ramasubramanian * engine 486eddac5afSKarthikeyan Ramasubramanian * @se: Pointer to the concerned serial engine. 487eddac5afSKarthikeyan Ramasubramanian * 488eddac5afSKarthikeyan Ramasubramanian * Return: 0 on success, standard Linux error codes on failure/error. 489eddac5afSKarthikeyan Ramasubramanian */ 490eddac5afSKarthikeyan Ramasubramanian int geni_se_resources_on(struct geni_se *se) 491eddac5afSKarthikeyan Ramasubramanian { 492eddac5afSKarthikeyan Ramasubramanian int ret; 493eddac5afSKarthikeyan Ramasubramanian 494*8bc529b2SLee Jones if (has_acpi_companion(se->dev)) 495*8bc529b2SLee Jones return 0; 496*8bc529b2SLee Jones 497eddac5afSKarthikeyan Ramasubramanian ret = geni_se_clks_on(se); 498eddac5afSKarthikeyan Ramasubramanian if (ret) 499eddac5afSKarthikeyan Ramasubramanian return ret; 500eddac5afSKarthikeyan Ramasubramanian 501eddac5afSKarthikeyan Ramasubramanian ret = pinctrl_pm_select_default_state(se->dev); 502eddac5afSKarthikeyan Ramasubramanian if (ret) 503eddac5afSKarthikeyan Ramasubramanian geni_se_clks_off(se); 504eddac5afSKarthikeyan Ramasubramanian 505eddac5afSKarthikeyan Ramasubramanian return ret; 506eddac5afSKarthikeyan Ramasubramanian } 507eddac5afSKarthikeyan Ramasubramanian EXPORT_SYMBOL(geni_se_resources_on); 508eddac5afSKarthikeyan Ramasubramanian 509eddac5afSKarthikeyan Ramasubramanian /** 510eddac5afSKarthikeyan Ramasubramanian * geni_se_clk_tbl_get() - Get the clock table to program DFS 511eddac5afSKarthikeyan Ramasubramanian * @se: Pointer to the concerned serial engine. 512eddac5afSKarthikeyan Ramasubramanian * @tbl: Table in which the output is returned. 513eddac5afSKarthikeyan Ramasubramanian * 514eddac5afSKarthikeyan Ramasubramanian * This function is called by the protocol drivers to determine the different 515eddac5afSKarthikeyan Ramasubramanian * clock frequencies supported by serial engine core clock. The protocol 516eddac5afSKarthikeyan Ramasubramanian * drivers use the output to determine the clock frequency index to be 517eddac5afSKarthikeyan Ramasubramanian * programmed into DFS. 518eddac5afSKarthikeyan Ramasubramanian * 519eddac5afSKarthikeyan Ramasubramanian * Return: number of valid performance levels in the table on success, 520eddac5afSKarthikeyan Ramasubramanian * standard Linux error codes on failure. 521eddac5afSKarthikeyan Ramasubramanian */ 522eddac5afSKarthikeyan Ramasubramanian int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) 523eddac5afSKarthikeyan Ramasubramanian { 524abc1c944SDouglas Anderson long freq = 0; 525eddac5afSKarthikeyan Ramasubramanian int i; 526eddac5afSKarthikeyan Ramasubramanian 527eddac5afSKarthikeyan Ramasubramanian if (se->clk_perf_tbl) { 528eddac5afSKarthikeyan Ramasubramanian *tbl = se->clk_perf_tbl; 529eddac5afSKarthikeyan Ramasubramanian return se->num_clk_levels; 530eddac5afSKarthikeyan Ramasubramanian } 531eddac5afSKarthikeyan Ramasubramanian 532eddac5afSKarthikeyan Ramasubramanian se->clk_perf_tbl = devm_kcalloc(se->dev, MAX_CLK_PERF_LEVEL, 533eddac5afSKarthikeyan Ramasubramanian sizeof(*se->clk_perf_tbl), 534eddac5afSKarthikeyan Ramasubramanian GFP_KERNEL); 535eddac5afSKarthikeyan Ramasubramanian if (!se->clk_perf_tbl) 536eddac5afSKarthikeyan Ramasubramanian return -ENOMEM; 537eddac5afSKarthikeyan Ramasubramanian 538eddac5afSKarthikeyan Ramasubramanian for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) { 539eddac5afSKarthikeyan Ramasubramanian freq = clk_round_rate(se->clk, freq + 1); 540abc1c944SDouglas Anderson if (freq <= 0 || freq == se->clk_perf_tbl[i - 1]) 541eddac5afSKarthikeyan Ramasubramanian break; 542eddac5afSKarthikeyan Ramasubramanian se->clk_perf_tbl[i] = freq; 543eddac5afSKarthikeyan Ramasubramanian } 544eddac5afSKarthikeyan Ramasubramanian se->num_clk_levels = i; 545eddac5afSKarthikeyan Ramasubramanian *tbl = se->clk_perf_tbl; 546eddac5afSKarthikeyan Ramasubramanian return se->num_clk_levels; 547eddac5afSKarthikeyan Ramasubramanian } 548eddac5afSKarthikeyan Ramasubramanian EXPORT_SYMBOL(geni_se_clk_tbl_get); 549eddac5afSKarthikeyan Ramasubramanian 550eddac5afSKarthikeyan Ramasubramanian /** 551eddac5afSKarthikeyan Ramasubramanian * geni_se_clk_freq_match() - Get the matching or closest SE clock frequency 552eddac5afSKarthikeyan Ramasubramanian * @se: Pointer to the concerned serial engine. 553eddac5afSKarthikeyan Ramasubramanian * @req_freq: Requested clock frequency. 554eddac5afSKarthikeyan Ramasubramanian * @index: Index of the resultant frequency in the table. 555969fc78cSDouglas Anderson * @res_freq: Resultant frequency of the source clock. 556eddac5afSKarthikeyan Ramasubramanian * @exact: Flag to indicate exact multiple requirement of the requested 557eddac5afSKarthikeyan Ramasubramanian * frequency. 558eddac5afSKarthikeyan Ramasubramanian * 559969fc78cSDouglas Anderson * This function is called by the protocol drivers to determine the best match 560969fc78cSDouglas Anderson * of the requested frequency as provided by the serial engine clock in order 561969fc78cSDouglas Anderson * to meet the performance requirements. 562969fc78cSDouglas Anderson * 563969fc78cSDouglas Anderson * If we return success: 564969fc78cSDouglas Anderson * - if @exact is true then @res_freq / <an_integer> == @req_freq 565969fc78cSDouglas Anderson * - if @exact is false then @res_freq / <an_integer> <= @req_freq 566eddac5afSKarthikeyan Ramasubramanian * 567eddac5afSKarthikeyan Ramasubramanian * Return: 0 on success, standard Linux error codes on failure. 568eddac5afSKarthikeyan Ramasubramanian */ 569eddac5afSKarthikeyan Ramasubramanian int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq, 570eddac5afSKarthikeyan Ramasubramanian unsigned int *index, unsigned long *res_freq, 571eddac5afSKarthikeyan Ramasubramanian bool exact) 572eddac5afSKarthikeyan Ramasubramanian { 573eddac5afSKarthikeyan Ramasubramanian unsigned long *tbl; 574eddac5afSKarthikeyan Ramasubramanian int num_clk_levels; 575eddac5afSKarthikeyan Ramasubramanian int i; 576969fc78cSDouglas Anderson unsigned long best_delta; 577969fc78cSDouglas Anderson unsigned long new_delta; 578969fc78cSDouglas Anderson unsigned int divider; 579eddac5afSKarthikeyan Ramasubramanian 580eddac5afSKarthikeyan Ramasubramanian num_clk_levels = geni_se_clk_tbl_get(se, &tbl); 581eddac5afSKarthikeyan Ramasubramanian if (num_clk_levels < 0) 582eddac5afSKarthikeyan Ramasubramanian return num_clk_levels; 583eddac5afSKarthikeyan Ramasubramanian 584eddac5afSKarthikeyan Ramasubramanian if (num_clk_levels == 0) 585eddac5afSKarthikeyan Ramasubramanian return -EINVAL; 586eddac5afSKarthikeyan Ramasubramanian 587969fc78cSDouglas Anderson best_delta = ULONG_MAX; 588eddac5afSKarthikeyan Ramasubramanian for (i = 0; i < num_clk_levels; i++) { 589969fc78cSDouglas Anderson divider = DIV_ROUND_UP(tbl[i], req_freq); 590969fc78cSDouglas Anderson new_delta = req_freq - tbl[i] / divider; 591969fc78cSDouglas Anderson if (new_delta < best_delta) { 592969fc78cSDouglas Anderson /* We have a new best! */ 593eddac5afSKarthikeyan Ramasubramanian *index = i; 594eddac5afSKarthikeyan Ramasubramanian *res_freq = tbl[i]; 595eddac5afSKarthikeyan Ramasubramanian 596969fc78cSDouglas Anderson /* If the new best is exact then we're done */ 597969fc78cSDouglas Anderson if (new_delta == 0) 598969fc78cSDouglas Anderson return 0; 599969fc78cSDouglas Anderson 600969fc78cSDouglas Anderson /* Record how close we got */ 601969fc78cSDouglas Anderson best_delta = new_delta; 602eddac5afSKarthikeyan Ramasubramanian } 603eddac5afSKarthikeyan Ramasubramanian } 604eddac5afSKarthikeyan Ramasubramanian 605eddac5afSKarthikeyan Ramasubramanian if (exact) 606eddac5afSKarthikeyan Ramasubramanian return -EINVAL; 607eddac5afSKarthikeyan Ramasubramanian 608eddac5afSKarthikeyan Ramasubramanian return 0; 609eddac5afSKarthikeyan Ramasubramanian } 610eddac5afSKarthikeyan Ramasubramanian EXPORT_SYMBOL(geni_se_clk_freq_match); 611eddac5afSKarthikeyan Ramasubramanian 612eddac5afSKarthikeyan Ramasubramanian #define GENI_SE_DMA_DONE_EN BIT(0) 613eddac5afSKarthikeyan Ramasubramanian #define GENI_SE_DMA_EOT_EN BIT(1) 614eddac5afSKarthikeyan Ramasubramanian #define GENI_SE_DMA_AHB_ERR_EN BIT(2) 615eddac5afSKarthikeyan Ramasubramanian #define GENI_SE_DMA_EOT_BUF BIT(0) 616eddac5afSKarthikeyan Ramasubramanian /** 617eddac5afSKarthikeyan Ramasubramanian * geni_se_tx_dma_prep() - Prepare the serial engine for TX DMA transfer 618eddac5afSKarthikeyan Ramasubramanian * @se: Pointer to the concerned serial engine. 619eddac5afSKarthikeyan Ramasubramanian * @buf: Pointer to the TX buffer. 620eddac5afSKarthikeyan Ramasubramanian * @len: Length of the TX buffer. 621eddac5afSKarthikeyan Ramasubramanian * @iova: Pointer to store the mapped DMA address. 622eddac5afSKarthikeyan Ramasubramanian * 623eddac5afSKarthikeyan Ramasubramanian * This function is used to prepare the buffers for DMA TX. 624eddac5afSKarthikeyan Ramasubramanian * 625eddac5afSKarthikeyan Ramasubramanian * Return: 0 on success, standard Linux error codes on failure. 626eddac5afSKarthikeyan Ramasubramanian */ 627eddac5afSKarthikeyan Ramasubramanian int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len, 628eddac5afSKarthikeyan Ramasubramanian dma_addr_t *iova) 629eddac5afSKarthikeyan Ramasubramanian { 630eddac5afSKarthikeyan Ramasubramanian struct geni_wrapper *wrapper = se->wrapper; 631eddac5afSKarthikeyan Ramasubramanian u32 val; 632eddac5afSKarthikeyan Ramasubramanian 633eddac5afSKarthikeyan Ramasubramanian *iova = dma_map_single(wrapper->dev, buf, len, DMA_TO_DEVICE); 634eddac5afSKarthikeyan Ramasubramanian if (dma_mapping_error(wrapper->dev, *iova)) 635eddac5afSKarthikeyan Ramasubramanian return -EIO; 636eddac5afSKarthikeyan Ramasubramanian 637eddac5afSKarthikeyan Ramasubramanian val = GENI_SE_DMA_DONE_EN; 638eddac5afSKarthikeyan Ramasubramanian val |= GENI_SE_DMA_EOT_EN; 639eddac5afSKarthikeyan Ramasubramanian val |= GENI_SE_DMA_AHB_ERR_EN; 640eddac5afSKarthikeyan Ramasubramanian writel_relaxed(val, se->base + SE_DMA_TX_IRQ_EN_SET); 641eddac5afSKarthikeyan Ramasubramanian writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_TX_PTR_L); 642eddac5afSKarthikeyan Ramasubramanian writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_TX_PTR_H); 643eddac5afSKarthikeyan Ramasubramanian writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR); 644eddac5afSKarthikeyan Ramasubramanian writel_relaxed(len, se->base + SE_DMA_TX_LEN); 645eddac5afSKarthikeyan Ramasubramanian return 0; 646eddac5afSKarthikeyan Ramasubramanian } 647eddac5afSKarthikeyan Ramasubramanian EXPORT_SYMBOL(geni_se_tx_dma_prep); 648eddac5afSKarthikeyan Ramasubramanian 649eddac5afSKarthikeyan Ramasubramanian /** 650eddac5afSKarthikeyan Ramasubramanian * geni_se_rx_dma_prep() - Prepare the serial engine for RX DMA transfer 651eddac5afSKarthikeyan Ramasubramanian * @se: Pointer to the concerned serial engine. 652eddac5afSKarthikeyan Ramasubramanian * @buf: Pointer to the RX buffer. 653eddac5afSKarthikeyan Ramasubramanian * @len: Length of the RX buffer. 654eddac5afSKarthikeyan Ramasubramanian * @iova: Pointer to store the mapped DMA address. 655eddac5afSKarthikeyan Ramasubramanian * 656eddac5afSKarthikeyan Ramasubramanian * This function is used to prepare the buffers for DMA RX. 657eddac5afSKarthikeyan Ramasubramanian * 658eddac5afSKarthikeyan Ramasubramanian * Return: 0 on success, standard Linux error codes on failure. 659eddac5afSKarthikeyan Ramasubramanian */ 660eddac5afSKarthikeyan Ramasubramanian int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len, 661eddac5afSKarthikeyan Ramasubramanian dma_addr_t *iova) 662eddac5afSKarthikeyan Ramasubramanian { 663eddac5afSKarthikeyan Ramasubramanian struct geni_wrapper *wrapper = se->wrapper; 664eddac5afSKarthikeyan Ramasubramanian u32 val; 665eddac5afSKarthikeyan Ramasubramanian 666eddac5afSKarthikeyan Ramasubramanian *iova = dma_map_single(wrapper->dev, buf, len, DMA_FROM_DEVICE); 667eddac5afSKarthikeyan Ramasubramanian if (dma_mapping_error(wrapper->dev, *iova)) 668eddac5afSKarthikeyan Ramasubramanian return -EIO; 669eddac5afSKarthikeyan Ramasubramanian 670eddac5afSKarthikeyan Ramasubramanian val = GENI_SE_DMA_DONE_EN; 671eddac5afSKarthikeyan Ramasubramanian val |= GENI_SE_DMA_EOT_EN; 672eddac5afSKarthikeyan Ramasubramanian val |= GENI_SE_DMA_AHB_ERR_EN; 673eddac5afSKarthikeyan Ramasubramanian writel_relaxed(val, se->base + SE_DMA_RX_IRQ_EN_SET); 674eddac5afSKarthikeyan Ramasubramanian writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_RX_PTR_L); 675eddac5afSKarthikeyan Ramasubramanian writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_RX_PTR_H); 676eddac5afSKarthikeyan Ramasubramanian /* RX does not have EOT buffer type bit. So just reset RX_ATTR */ 677eddac5afSKarthikeyan Ramasubramanian writel_relaxed(0, se->base + SE_DMA_RX_ATTR); 678eddac5afSKarthikeyan Ramasubramanian writel_relaxed(len, se->base + SE_DMA_RX_LEN); 679eddac5afSKarthikeyan Ramasubramanian return 0; 680eddac5afSKarthikeyan Ramasubramanian } 681eddac5afSKarthikeyan Ramasubramanian EXPORT_SYMBOL(geni_se_rx_dma_prep); 682eddac5afSKarthikeyan Ramasubramanian 683eddac5afSKarthikeyan Ramasubramanian /** 684eddac5afSKarthikeyan Ramasubramanian * geni_se_tx_dma_unprep() - Unprepare the serial engine after TX DMA transfer 685eddac5afSKarthikeyan Ramasubramanian * @se: Pointer to the concerned serial engine. 686eddac5afSKarthikeyan Ramasubramanian * @iova: DMA address of the TX buffer. 687eddac5afSKarthikeyan Ramasubramanian * @len: Length of the TX buffer. 688eddac5afSKarthikeyan Ramasubramanian * 689eddac5afSKarthikeyan Ramasubramanian * This function is used to unprepare the DMA buffers after DMA TX. 690eddac5afSKarthikeyan Ramasubramanian */ 691eddac5afSKarthikeyan Ramasubramanian void geni_se_tx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len) 692eddac5afSKarthikeyan Ramasubramanian { 693eddac5afSKarthikeyan Ramasubramanian struct geni_wrapper *wrapper = se->wrapper; 694eddac5afSKarthikeyan Ramasubramanian 695eddac5afSKarthikeyan Ramasubramanian if (iova && !dma_mapping_error(wrapper->dev, iova)) 696eddac5afSKarthikeyan Ramasubramanian dma_unmap_single(wrapper->dev, iova, len, DMA_TO_DEVICE); 697eddac5afSKarthikeyan Ramasubramanian } 698eddac5afSKarthikeyan Ramasubramanian EXPORT_SYMBOL(geni_se_tx_dma_unprep); 699eddac5afSKarthikeyan Ramasubramanian 700eddac5afSKarthikeyan Ramasubramanian /** 701eddac5afSKarthikeyan Ramasubramanian * geni_se_rx_dma_unprep() - Unprepare the serial engine after RX DMA transfer 702eddac5afSKarthikeyan Ramasubramanian * @se: Pointer to the concerned serial engine. 703eddac5afSKarthikeyan Ramasubramanian * @iova: DMA address of the RX buffer. 704eddac5afSKarthikeyan Ramasubramanian * @len: Length of the RX buffer. 705eddac5afSKarthikeyan Ramasubramanian * 706eddac5afSKarthikeyan Ramasubramanian * This function is used to unprepare the DMA buffers after DMA RX. 707eddac5afSKarthikeyan Ramasubramanian */ 708eddac5afSKarthikeyan Ramasubramanian void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len) 709eddac5afSKarthikeyan Ramasubramanian { 710eddac5afSKarthikeyan Ramasubramanian struct geni_wrapper *wrapper = se->wrapper; 711eddac5afSKarthikeyan Ramasubramanian 712eddac5afSKarthikeyan Ramasubramanian if (iova && !dma_mapping_error(wrapper->dev, iova)) 713eddac5afSKarthikeyan Ramasubramanian dma_unmap_single(wrapper->dev, iova, len, DMA_FROM_DEVICE); 714eddac5afSKarthikeyan Ramasubramanian } 715eddac5afSKarthikeyan Ramasubramanian EXPORT_SYMBOL(geni_se_rx_dma_unprep); 716eddac5afSKarthikeyan Ramasubramanian 717eddac5afSKarthikeyan Ramasubramanian static int geni_se_probe(struct platform_device *pdev) 718eddac5afSKarthikeyan Ramasubramanian { 719eddac5afSKarthikeyan Ramasubramanian struct device *dev = &pdev->dev; 720eddac5afSKarthikeyan Ramasubramanian struct resource *res; 721eddac5afSKarthikeyan Ramasubramanian struct geni_wrapper *wrapper; 722eddac5afSKarthikeyan Ramasubramanian int ret; 723eddac5afSKarthikeyan Ramasubramanian 724eddac5afSKarthikeyan Ramasubramanian wrapper = devm_kzalloc(dev, sizeof(*wrapper), GFP_KERNEL); 725eddac5afSKarthikeyan Ramasubramanian if (!wrapper) 726eddac5afSKarthikeyan Ramasubramanian return -ENOMEM; 727eddac5afSKarthikeyan Ramasubramanian 728eddac5afSKarthikeyan Ramasubramanian wrapper->dev = dev; 729eddac5afSKarthikeyan Ramasubramanian res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 730eddac5afSKarthikeyan Ramasubramanian wrapper->base = devm_ioremap_resource(dev, res); 731eddac5afSKarthikeyan Ramasubramanian if (IS_ERR(wrapper->base)) 732eddac5afSKarthikeyan Ramasubramanian return PTR_ERR(wrapper->base); 733eddac5afSKarthikeyan Ramasubramanian 734*8bc529b2SLee Jones if (!has_acpi_companion(&pdev->dev)) { 735eddac5afSKarthikeyan Ramasubramanian wrapper->ahb_clks[0].id = "m-ahb"; 736eddac5afSKarthikeyan Ramasubramanian wrapper->ahb_clks[1].id = "s-ahb"; 737eddac5afSKarthikeyan Ramasubramanian ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks); 738eddac5afSKarthikeyan Ramasubramanian if (ret) { 739eddac5afSKarthikeyan Ramasubramanian dev_err(dev, "Err getting AHB clks %d\n", ret); 740eddac5afSKarthikeyan Ramasubramanian return ret; 741eddac5afSKarthikeyan Ramasubramanian } 742*8bc529b2SLee Jones } 743eddac5afSKarthikeyan Ramasubramanian 744eddac5afSKarthikeyan Ramasubramanian dev_set_drvdata(dev, wrapper); 745eddac5afSKarthikeyan Ramasubramanian dev_dbg(dev, "GENI SE Driver probed\n"); 746eddac5afSKarthikeyan Ramasubramanian return devm_of_platform_populate(dev); 747eddac5afSKarthikeyan Ramasubramanian } 748eddac5afSKarthikeyan Ramasubramanian 749eddac5afSKarthikeyan Ramasubramanian static const struct of_device_id geni_se_dt_match[] = { 750eddac5afSKarthikeyan Ramasubramanian { .compatible = "qcom,geni-se-qup", }, 751eddac5afSKarthikeyan Ramasubramanian {} 752eddac5afSKarthikeyan Ramasubramanian }; 753eddac5afSKarthikeyan Ramasubramanian MODULE_DEVICE_TABLE(of, geni_se_dt_match); 754eddac5afSKarthikeyan Ramasubramanian 755eddac5afSKarthikeyan Ramasubramanian static struct platform_driver geni_se_driver = { 756eddac5afSKarthikeyan Ramasubramanian .driver = { 757eddac5afSKarthikeyan Ramasubramanian .name = "geni_se_qup", 758eddac5afSKarthikeyan Ramasubramanian .of_match_table = geni_se_dt_match, 759eddac5afSKarthikeyan Ramasubramanian }, 760eddac5afSKarthikeyan Ramasubramanian .probe = geni_se_probe, 761eddac5afSKarthikeyan Ramasubramanian }; 762eddac5afSKarthikeyan Ramasubramanian module_platform_driver(geni_se_driver); 763eddac5afSKarthikeyan Ramasubramanian 764eddac5afSKarthikeyan Ramasubramanian MODULE_DESCRIPTION("GENI Serial Engine Driver"); 765eddac5afSKarthikeyan Ramasubramanian MODULE_LICENSE("GPL v2"); 766