1fcacb5c1SSuzuki K Poulose // SPDX-License-Identifier: GPL-2.0
2fcacb5c1SSuzuki K Poulose /*
3fcacb5c1SSuzuki K Poulose * Copyright (C) 2018 Arm Limited. All rights reserved.
4fcacb5c1SSuzuki K Poulose *
5fcacb5c1SSuzuki K Poulose * Coresight Address Translation Unit support
6fcacb5c1SSuzuki K Poulose *
7fcacb5c1SSuzuki K Poulose * Author: Suzuki K Poulose <suzuki.poulose@arm.com>
8fcacb5c1SSuzuki K Poulose */
9fcacb5c1SSuzuki K Poulose
10fcacb5c1SSuzuki K Poulose #include <linux/amba/bus.h>
11fcacb5c1SSuzuki K Poulose #include <linux/device.h>
12fcacb5c1SSuzuki K Poulose #include <linux/dma-mapping.h>
13fcacb5c1SSuzuki K Poulose #include <linux/io.h>
14fcacb5c1SSuzuki K Poulose #include <linux/kernel.h>
15fcacb5c1SSuzuki K Poulose #include <linux/slab.h>
16fcacb5c1SSuzuki K Poulose
17fcacb5c1SSuzuki K Poulose #include "coresight-catu.h"
18fcacb5c1SSuzuki K Poulose #include "coresight-priv.h"
198ed536b1SSuzuki K Poulose #include "coresight-tmc.h"
20fcacb5c1SSuzuki K Poulose
21fcacb5c1SSuzuki K Poulose #define csdev_to_catu_drvdata(csdev) \
22fcacb5c1SSuzuki K Poulose dev_get_drvdata(csdev->dev.parent)
23fcacb5c1SSuzuki K Poulose
248ed536b1SSuzuki K Poulose /* Verbose output for CATU table contents */
258ed536b1SSuzuki K Poulose #ifdef CATU_DEBUG
268ed536b1SSuzuki K Poulose #define catu_dbg(x, ...) dev_dbg(x, __VA_ARGS__)
278ed536b1SSuzuki K Poulose #else
288ed536b1SSuzuki K Poulose #define catu_dbg(x, ...) do {} while (0)
298ed536b1SSuzuki K Poulose #endif
308ed536b1SSuzuki K Poulose
310f5f9b6bSSuzuki K Poulose DEFINE_CORESIGHT_DEVLIST(catu_devs, "catu");
320f5f9b6bSSuzuki K Poulose
33434d611cSSuzuki K Poulose struct catu_etr_buf {
34434d611cSSuzuki K Poulose struct tmc_sg_table *catu_table;
35434d611cSSuzuki K Poulose dma_addr_t sladdr;
36434d611cSSuzuki K Poulose };
37434d611cSSuzuki K Poulose
388ed536b1SSuzuki K Poulose /*
398ed536b1SSuzuki K Poulose * CATU uses a page size of 4KB for page tables as well as data pages.
408ed536b1SSuzuki K Poulose * Each 64bit entry in the table has the following format.
418ed536b1SSuzuki K Poulose *
428ed536b1SSuzuki K Poulose * 63 12 1 0
438ed536b1SSuzuki K Poulose * ------------------------------------
448ed536b1SSuzuki K Poulose * | Address [63-12] | SBZ | V|
458ed536b1SSuzuki K Poulose * ------------------------------------
468ed536b1SSuzuki K Poulose *
478ed536b1SSuzuki K Poulose * Where bit[0] V indicates if the address is valid or not.
488ed536b1SSuzuki K Poulose * Each 4K table pages have upto 256 data page pointers, taking upto 2K
498ed536b1SSuzuki K Poulose * size. There are two Link pointers, pointing to the previous and next
508ed536b1SSuzuki K Poulose * table pages respectively at the end of the 4K page. (i.e, entry 510
518ed536b1SSuzuki K Poulose * and 511).
528ed536b1SSuzuki K Poulose * E.g, a table of two pages could look like :
538ed536b1SSuzuki K Poulose *
548ed536b1SSuzuki K Poulose * Table Page 0 Table Page 1
558ed536b1SSuzuki K Poulose * SLADDR ===> x------------------x x--> x-----------------x
568ed536b1SSuzuki K Poulose * INADDR ->| Page 0 | V | | | Page 256 | V | <- INADDR+1M
578ed536b1SSuzuki K Poulose * |------------------| | |-----------------|
588ed536b1SSuzuki K Poulose * INADDR+4K ->| Page 1 | V | | | |
598ed536b1SSuzuki K Poulose * |------------------| | |-----------------|
608ed536b1SSuzuki K Poulose * | Page 2 | V | | | |
618ed536b1SSuzuki K Poulose * |------------------| | |-----------------|
628ed536b1SSuzuki K Poulose * | ... | V | | | ... |
638ed536b1SSuzuki K Poulose * |------------------| | |-----------------|
648ed536b1SSuzuki K Poulose * INADDR+1020K| Page 255 | V | | | Page 511 | V |
658ed536b1SSuzuki K Poulose * SLADDR+2K==>|------------------| | |-----------------|
668ed536b1SSuzuki K Poulose * | UNUSED | | | | |
678ed536b1SSuzuki K Poulose * |------------------| | | |
688ed536b1SSuzuki K Poulose * | UNUSED | | | | |
698ed536b1SSuzuki K Poulose * |------------------| | | |
708ed536b1SSuzuki K Poulose * | ... | | | | |
718ed536b1SSuzuki K Poulose * |------------------| | |-----------------|
728ed536b1SSuzuki K Poulose * | IGNORED | 0 | | | Table Page 0| 1 |
738ed536b1SSuzuki K Poulose * |------------------| | |-----------------|
748ed536b1SSuzuki K Poulose * | Table Page 1| 1 |--x | IGNORED | 0 |
758ed536b1SSuzuki K Poulose * x------------------x x-----------------x
768ed536b1SSuzuki K Poulose * SLADDR+4K==>
778ed536b1SSuzuki K Poulose *
788ed536b1SSuzuki K Poulose * The base input address (used by the ETR, programmed in INADDR_{LO,HI})
798ed536b1SSuzuki K Poulose * must be aligned to 1MB (the size addressable by a single page table).
808ed536b1SSuzuki K Poulose * The CATU maps INADDR{LO:HI} to the first page in the table pointed
818ed536b1SSuzuki K Poulose * to by SLADDR{LO:HI} and so on.
828ed536b1SSuzuki K Poulose *
838ed536b1SSuzuki K Poulose */
848ed536b1SSuzuki K Poulose typedef u64 cate_t;
858ed536b1SSuzuki K Poulose
868ed536b1SSuzuki K Poulose #define CATU_PAGE_SHIFT 12
878ed536b1SSuzuki K Poulose #define CATU_PAGE_SIZE (1UL << CATU_PAGE_SHIFT)
888ed536b1SSuzuki K Poulose #define CATU_PAGES_PER_SYSPAGE (PAGE_SIZE / CATU_PAGE_SIZE)
898ed536b1SSuzuki K Poulose
908ed536b1SSuzuki K Poulose /* Page pointers are only allocated in the first 2K half */
918ed536b1SSuzuki K Poulose #define CATU_PTRS_PER_PAGE ((CATU_PAGE_SIZE >> 1) / sizeof(cate_t))
928ed536b1SSuzuki K Poulose #define CATU_PTRS_PER_SYSPAGE (CATU_PAGES_PER_SYSPAGE * CATU_PTRS_PER_PAGE)
938ed536b1SSuzuki K Poulose #define CATU_LINK_PREV ((CATU_PAGE_SIZE / sizeof(cate_t)) - 2)
948ed536b1SSuzuki K Poulose #define CATU_LINK_NEXT ((CATU_PAGE_SIZE / sizeof(cate_t)) - 1)
958ed536b1SSuzuki K Poulose
968ed536b1SSuzuki K Poulose #define CATU_ADDR_SHIFT 12
978ed536b1SSuzuki K Poulose #define CATU_ADDR_MASK ~(((cate_t)1 << CATU_ADDR_SHIFT) - 1)
988ed536b1SSuzuki K Poulose #define CATU_ENTRY_VALID ((cate_t)0x1)
998ed536b1SSuzuki K Poulose #define CATU_VALID_ENTRY(addr) \
1008ed536b1SSuzuki K Poulose (((cate_t)(addr) & CATU_ADDR_MASK) | CATU_ENTRY_VALID)
1018ed536b1SSuzuki K Poulose #define CATU_ENTRY_ADDR(entry) ((cate_t)(entry) & ~((cate_t)CATU_ENTRY_VALID))
1028ed536b1SSuzuki K Poulose
103434d611cSSuzuki K Poulose /* CATU expects the INADDR to be aligned to 1M. */
104434d611cSSuzuki K Poulose #define CATU_DEFAULT_INADDR (1ULL << 20)
105434d611cSSuzuki K Poulose
1068ed536b1SSuzuki K Poulose /*
1078ed536b1SSuzuki K Poulose * catu_get_table : Retrieve the table pointers for the given @offset
1088ed536b1SSuzuki K Poulose * within the buffer. The buffer is wrapped around to a valid offset.
1098ed536b1SSuzuki K Poulose *
1108ed536b1SSuzuki K Poulose * Returns : The CPU virtual address for the beginning of the table
1118ed536b1SSuzuki K Poulose * containing the data page pointer for @offset. If @daddrp is not NULL,
1128ed536b1SSuzuki K Poulose * @daddrp points the DMA address of the beginning of the table.
1138ed536b1SSuzuki K Poulose */
catu_get_table(struct tmc_sg_table * catu_table,unsigned long offset,dma_addr_t * daddrp)1148ed536b1SSuzuki K Poulose static inline cate_t *catu_get_table(struct tmc_sg_table *catu_table,
1158ed536b1SSuzuki K Poulose unsigned long offset,
1168ed536b1SSuzuki K Poulose dma_addr_t *daddrp)
1178ed536b1SSuzuki K Poulose {
1188ed536b1SSuzuki K Poulose unsigned long buf_size = tmc_sg_table_buf_size(catu_table);
1198ed536b1SSuzuki K Poulose unsigned int table_nr, pg_idx, pg_offset;
1208ed536b1SSuzuki K Poulose struct tmc_pages *table_pages = &catu_table->table_pages;
1218ed536b1SSuzuki K Poulose void *ptr;
1228ed536b1SSuzuki K Poulose
1238ed536b1SSuzuki K Poulose /* Make sure offset is within the range */
1248ed536b1SSuzuki K Poulose offset %= buf_size;
1258ed536b1SSuzuki K Poulose
1268ed536b1SSuzuki K Poulose /*
1278ed536b1SSuzuki K Poulose * Each table can address 1MB and a single kernel page can
1288ed536b1SSuzuki K Poulose * contain "CATU_PAGES_PER_SYSPAGE" CATU tables.
1298ed536b1SSuzuki K Poulose */
1308ed536b1SSuzuki K Poulose table_nr = offset >> 20;
1318ed536b1SSuzuki K Poulose /* Find the table page where the table_nr lies in */
1328ed536b1SSuzuki K Poulose pg_idx = table_nr / CATU_PAGES_PER_SYSPAGE;
1338ed536b1SSuzuki K Poulose pg_offset = (table_nr % CATU_PAGES_PER_SYSPAGE) * CATU_PAGE_SIZE;
1348ed536b1SSuzuki K Poulose if (daddrp)
1358ed536b1SSuzuki K Poulose *daddrp = table_pages->daddrs[pg_idx] + pg_offset;
1368ed536b1SSuzuki K Poulose ptr = page_address(table_pages->pages[pg_idx]);
1378ed536b1SSuzuki K Poulose return (cate_t *)((unsigned long)ptr + pg_offset);
1388ed536b1SSuzuki K Poulose }
1398ed536b1SSuzuki K Poulose
1408ed536b1SSuzuki K Poulose #ifdef CATU_DEBUG
catu_dump_table(struct tmc_sg_table * catu_table)1418ed536b1SSuzuki K Poulose static void catu_dump_table(struct tmc_sg_table *catu_table)
1428ed536b1SSuzuki K Poulose {
1438ed536b1SSuzuki K Poulose int i;
1448ed536b1SSuzuki K Poulose cate_t *table;
1458ed536b1SSuzuki K Poulose unsigned long table_end, buf_size, offset = 0;
1468ed536b1SSuzuki K Poulose
1478ed536b1SSuzuki K Poulose buf_size = tmc_sg_table_buf_size(catu_table);
1488ed536b1SSuzuki K Poulose dev_dbg(catu_table->dev,
1498ed536b1SSuzuki K Poulose "Dump table %p, tdaddr: %llx\n",
1508ed536b1SSuzuki K Poulose catu_table, catu_table->table_daddr);
1518ed536b1SSuzuki K Poulose
1528ed536b1SSuzuki K Poulose while (offset < buf_size) {
1538ed536b1SSuzuki K Poulose table_end = offset + SZ_1M < buf_size ?
1548ed536b1SSuzuki K Poulose offset + SZ_1M : buf_size;
1558ed536b1SSuzuki K Poulose table = catu_get_table(catu_table, offset, NULL);
1568ed536b1SSuzuki K Poulose for (i = 0; offset < table_end; i++, offset += CATU_PAGE_SIZE)
1578ed536b1SSuzuki K Poulose dev_dbg(catu_table->dev, "%d: %llx\n", i, table[i]);
1588ed536b1SSuzuki K Poulose dev_dbg(catu_table->dev, "Prev : %llx, Next: %llx\n",
1598ed536b1SSuzuki K Poulose table[CATU_LINK_PREV], table[CATU_LINK_NEXT]);
1608ed536b1SSuzuki K Poulose dev_dbg(catu_table->dev, "== End of sub-table ===");
1618ed536b1SSuzuki K Poulose }
1628ed536b1SSuzuki K Poulose dev_dbg(catu_table->dev, "== End of Table ===");
1638ed536b1SSuzuki K Poulose }
1648ed536b1SSuzuki K Poulose
1658ed536b1SSuzuki K Poulose #else
catu_dump_table(struct tmc_sg_table * catu_table)1668ed536b1SSuzuki K Poulose static inline void catu_dump_table(struct tmc_sg_table *catu_table)
1678ed536b1SSuzuki K Poulose {
1688ed536b1SSuzuki K Poulose }
1698ed536b1SSuzuki K Poulose #endif
1708ed536b1SSuzuki K Poulose
catu_make_entry(dma_addr_t addr)1718ed536b1SSuzuki K Poulose static inline cate_t catu_make_entry(dma_addr_t addr)
1728ed536b1SSuzuki K Poulose {
1738ed536b1SSuzuki K Poulose return addr ? CATU_VALID_ENTRY(addr) : 0;
1748ed536b1SSuzuki K Poulose }
1758ed536b1SSuzuki K Poulose
1768ed536b1SSuzuki K Poulose /*
1778ed536b1SSuzuki K Poulose * catu_populate_table : Populate the given CATU table.
1788ed536b1SSuzuki K Poulose * The table is always populated as a circular table.
1798ed536b1SSuzuki K Poulose * i.e, the "prev" link of the "first" table points to the "last"
1808ed536b1SSuzuki K Poulose * table and the "next" link of the "last" table points to the
1818ed536b1SSuzuki K Poulose * "first" table. The buffer should be made linear by calling
1828ed536b1SSuzuki K Poulose * catu_set_table().
1838ed536b1SSuzuki K Poulose */
1848ed536b1SSuzuki K Poulose static void
catu_populate_table(struct tmc_sg_table * catu_table)1858ed536b1SSuzuki K Poulose catu_populate_table(struct tmc_sg_table *catu_table)
1868ed536b1SSuzuki K Poulose {
1878ed536b1SSuzuki K Poulose int i;
1888ed536b1SSuzuki K Poulose int sys_pidx; /* Index to current system data page */
1898ed536b1SSuzuki K Poulose int catu_pidx; /* Index of CATU page within the system data page */
1908ed536b1SSuzuki K Poulose unsigned long offset, buf_size, table_end;
1918ed536b1SSuzuki K Poulose dma_addr_t data_daddr;
1928ed536b1SSuzuki K Poulose dma_addr_t prev_taddr, next_taddr, cur_taddr;
1938ed536b1SSuzuki K Poulose cate_t *table_ptr, *next_table;
1948ed536b1SSuzuki K Poulose
1958ed536b1SSuzuki K Poulose buf_size = tmc_sg_table_buf_size(catu_table);
1968ed536b1SSuzuki K Poulose sys_pidx = catu_pidx = 0;
1978ed536b1SSuzuki K Poulose offset = 0;
1988ed536b1SSuzuki K Poulose
1998ed536b1SSuzuki K Poulose table_ptr = catu_get_table(catu_table, 0, &cur_taddr);
2008ed536b1SSuzuki K Poulose prev_taddr = 0; /* Prev link for the first table */
2018ed536b1SSuzuki K Poulose
2028ed536b1SSuzuki K Poulose while (offset < buf_size) {
2038ed536b1SSuzuki K Poulose /*
2048ed536b1SSuzuki K Poulose * The @offset is always 1M aligned here and we have an
2058ed536b1SSuzuki K Poulose * empty table @table_ptr to fill. Each table can address
2068ed536b1SSuzuki K Poulose * upto 1MB data buffer. The last table may have fewer
2078ed536b1SSuzuki K Poulose * entries if the buffer size is not aligned.
2088ed536b1SSuzuki K Poulose */
2098ed536b1SSuzuki K Poulose table_end = (offset + SZ_1M) < buf_size ?
2108ed536b1SSuzuki K Poulose (offset + SZ_1M) : buf_size;
2118ed536b1SSuzuki K Poulose for (i = 0; offset < table_end;
2128ed536b1SSuzuki K Poulose i++, offset += CATU_PAGE_SIZE) {
2138ed536b1SSuzuki K Poulose
2148ed536b1SSuzuki K Poulose data_daddr = catu_table->data_pages.daddrs[sys_pidx] +
2158ed536b1SSuzuki K Poulose catu_pidx * CATU_PAGE_SIZE;
2168ed536b1SSuzuki K Poulose catu_dbg(catu_table->dev,
2178ed536b1SSuzuki K Poulose "[table %5ld:%03d] 0x%llx\n",
2188ed536b1SSuzuki K Poulose (offset >> 20), i, data_daddr);
2198ed536b1SSuzuki K Poulose table_ptr[i] = catu_make_entry(data_daddr);
2208ed536b1SSuzuki K Poulose /* Move the pointers for data pages */
2218ed536b1SSuzuki K Poulose catu_pidx = (catu_pidx + 1) % CATU_PAGES_PER_SYSPAGE;
2228ed536b1SSuzuki K Poulose if (catu_pidx == 0)
2238ed536b1SSuzuki K Poulose sys_pidx++;
2248ed536b1SSuzuki K Poulose }
2258ed536b1SSuzuki K Poulose
2268ed536b1SSuzuki K Poulose /*
2278ed536b1SSuzuki K Poulose * If we have finished all the valid entries, fill the rest of
2288ed536b1SSuzuki K Poulose * the table (i.e, last table page) with invalid entries,
2298ed536b1SSuzuki K Poulose * to fail the lookups.
2308ed536b1SSuzuki K Poulose */
2318ed536b1SSuzuki K Poulose if (offset == buf_size) {
2328ed536b1SSuzuki K Poulose memset(&table_ptr[i], 0,
2338ed536b1SSuzuki K Poulose sizeof(cate_t) * (CATU_PTRS_PER_PAGE - i));
2348ed536b1SSuzuki K Poulose next_taddr = 0;
2358ed536b1SSuzuki K Poulose } else {
2368ed536b1SSuzuki K Poulose next_table = catu_get_table(catu_table,
2378ed536b1SSuzuki K Poulose offset, &next_taddr);
2388ed536b1SSuzuki K Poulose }
2398ed536b1SSuzuki K Poulose
2408ed536b1SSuzuki K Poulose table_ptr[CATU_LINK_PREV] = catu_make_entry(prev_taddr);
2418ed536b1SSuzuki K Poulose table_ptr[CATU_LINK_NEXT] = catu_make_entry(next_taddr);
2428ed536b1SSuzuki K Poulose
2438ed536b1SSuzuki K Poulose catu_dbg(catu_table->dev,
2448ed536b1SSuzuki K Poulose "[table%5ld]: Cur: 0x%llx Prev: 0x%llx, Next: 0x%llx\n",
2458ed536b1SSuzuki K Poulose (offset >> 20) - 1, cur_taddr, prev_taddr, next_taddr);
2468ed536b1SSuzuki K Poulose
2478ed536b1SSuzuki K Poulose /* Update the prev/next addresses */
2488ed536b1SSuzuki K Poulose if (next_taddr) {
2498ed536b1SSuzuki K Poulose prev_taddr = cur_taddr;
2508ed536b1SSuzuki K Poulose cur_taddr = next_taddr;
2518ed536b1SSuzuki K Poulose table_ptr = next_table;
2528ed536b1SSuzuki K Poulose }
2538ed536b1SSuzuki K Poulose }
2548ed536b1SSuzuki K Poulose
2558ed536b1SSuzuki K Poulose /* Sync the table for device */
2568ed536b1SSuzuki K Poulose tmc_sg_table_sync_table(catu_table);
2578ed536b1SSuzuki K Poulose }
2588ed536b1SSuzuki K Poulose
259434d611cSSuzuki K Poulose static struct tmc_sg_table *
catu_init_sg_table(struct device * catu_dev,int node,ssize_t size,void ** pages)2608ed536b1SSuzuki K Poulose catu_init_sg_table(struct device *catu_dev, int node,
2618ed536b1SSuzuki K Poulose ssize_t size, void **pages)
2628ed536b1SSuzuki K Poulose {
2638ed536b1SSuzuki K Poulose int nr_tpages;
2648ed536b1SSuzuki K Poulose struct tmc_sg_table *catu_table;
2658ed536b1SSuzuki K Poulose
2668ed536b1SSuzuki K Poulose /*
2678ed536b1SSuzuki K Poulose * Each table can address upto 1MB and we can have
2688ed536b1SSuzuki K Poulose * CATU_PAGES_PER_SYSPAGE tables in a system page.
2698ed536b1SSuzuki K Poulose */
2708ed536b1SSuzuki K Poulose nr_tpages = DIV_ROUND_UP(size, SZ_1M) / CATU_PAGES_PER_SYSPAGE;
2718ed536b1SSuzuki K Poulose catu_table = tmc_alloc_sg_table(catu_dev, node, nr_tpages,
2728ed536b1SSuzuki K Poulose size >> PAGE_SHIFT, pages);
2738ed536b1SSuzuki K Poulose if (IS_ERR(catu_table))
2748ed536b1SSuzuki K Poulose return catu_table;
2758ed536b1SSuzuki K Poulose
2768ed536b1SSuzuki K Poulose catu_populate_table(catu_table);
2778ed536b1SSuzuki K Poulose dev_dbg(catu_dev,
2788ed536b1SSuzuki K Poulose "Setup table %p, size %ldKB, %d table pages\n",
2798ed536b1SSuzuki K Poulose catu_table, (unsigned long)size >> 10, nr_tpages);
2808ed536b1SSuzuki K Poulose catu_dump_table(catu_table);
2818ed536b1SSuzuki K Poulose return catu_table;
2828ed536b1SSuzuki K Poulose }
2838ed536b1SSuzuki K Poulose
catu_free_etr_buf(struct etr_buf * etr_buf)284434d611cSSuzuki K Poulose static void catu_free_etr_buf(struct etr_buf *etr_buf)
285434d611cSSuzuki K Poulose {
286434d611cSSuzuki K Poulose struct catu_etr_buf *catu_buf;
287434d611cSSuzuki K Poulose
288434d611cSSuzuki K Poulose if (!etr_buf || etr_buf->mode != ETR_MODE_CATU || !etr_buf->private)
289434d611cSSuzuki K Poulose return;
290434d611cSSuzuki K Poulose
291434d611cSSuzuki K Poulose catu_buf = etr_buf->private;
292434d611cSSuzuki K Poulose tmc_free_sg_table(catu_buf->catu_table);
293434d611cSSuzuki K Poulose kfree(catu_buf);
294434d611cSSuzuki K Poulose }
295434d611cSSuzuki K Poulose
catu_get_data_etr_buf(struct etr_buf * etr_buf,u64 offset,size_t len,char ** bufpp)296434d611cSSuzuki K Poulose static ssize_t catu_get_data_etr_buf(struct etr_buf *etr_buf, u64 offset,
297434d611cSSuzuki K Poulose size_t len, char **bufpp)
298434d611cSSuzuki K Poulose {
299434d611cSSuzuki K Poulose struct catu_etr_buf *catu_buf = etr_buf->private;
300434d611cSSuzuki K Poulose
301434d611cSSuzuki K Poulose return tmc_sg_table_get_data(catu_buf->catu_table, offset, len, bufpp);
302434d611cSSuzuki K Poulose }
303434d611cSSuzuki K Poulose
catu_sync_etr_buf(struct etr_buf * etr_buf,u64 rrp,u64 rwp)304434d611cSSuzuki K Poulose static void catu_sync_etr_buf(struct etr_buf *etr_buf, u64 rrp, u64 rwp)
305434d611cSSuzuki K Poulose {
306434d611cSSuzuki K Poulose struct catu_etr_buf *catu_buf = etr_buf->private;
307434d611cSSuzuki K Poulose struct tmc_sg_table *catu_table = catu_buf->catu_table;
308434d611cSSuzuki K Poulose u64 r_offset, w_offset;
309434d611cSSuzuki K Poulose
310434d611cSSuzuki K Poulose /*
311434d611cSSuzuki K Poulose * ETR started off at etr_buf->hwaddr. Convert the RRP/RWP to
312434d611cSSuzuki K Poulose * offsets within the trace buffer.
313434d611cSSuzuki K Poulose */
314434d611cSSuzuki K Poulose r_offset = rrp - etr_buf->hwaddr;
315434d611cSSuzuki K Poulose w_offset = rwp - etr_buf->hwaddr;
316434d611cSSuzuki K Poulose
317434d611cSSuzuki K Poulose if (!etr_buf->full) {
318434d611cSSuzuki K Poulose etr_buf->len = w_offset - r_offset;
319434d611cSSuzuki K Poulose if (w_offset < r_offset)
320434d611cSSuzuki K Poulose etr_buf->len += etr_buf->size;
321434d611cSSuzuki K Poulose } else {
322434d611cSSuzuki K Poulose etr_buf->len = etr_buf->size;
323434d611cSSuzuki K Poulose }
324434d611cSSuzuki K Poulose
325434d611cSSuzuki K Poulose etr_buf->offset = r_offset;
326434d611cSSuzuki K Poulose tmc_sg_table_sync_data_range(catu_table, r_offset, etr_buf->len);
327434d611cSSuzuki K Poulose }
328434d611cSSuzuki K Poulose
catu_alloc_etr_buf(struct tmc_drvdata * tmc_drvdata,struct etr_buf * etr_buf,int node,void ** pages)329434d611cSSuzuki K Poulose static int catu_alloc_etr_buf(struct tmc_drvdata *tmc_drvdata,
330434d611cSSuzuki K Poulose struct etr_buf *etr_buf, int node, void **pages)
331434d611cSSuzuki K Poulose {
332434d611cSSuzuki K Poulose struct coresight_device *csdev;
333434d611cSSuzuki K Poulose struct tmc_sg_table *catu_table;
334434d611cSSuzuki K Poulose struct catu_etr_buf *catu_buf;
335434d611cSSuzuki K Poulose
336434d611cSSuzuki K Poulose csdev = tmc_etr_get_catu_device(tmc_drvdata);
337434d611cSSuzuki K Poulose if (!csdev)
338434d611cSSuzuki K Poulose return -ENODEV;
339434d611cSSuzuki K Poulose catu_buf = kzalloc(sizeof(*catu_buf), GFP_KERNEL);
340434d611cSSuzuki K Poulose if (!catu_buf)
341434d611cSSuzuki K Poulose return -ENOMEM;
342434d611cSSuzuki K Poulose
3439dd0a920SSuzuki K Poulose catu_table = catu_init_sg_table(&csdev->dev, node,
3449dd0a920SSuzuki K Poulose etr_buf->size, pages);
345434d611cSSuzuki K Poulose if (IS_ERR(catu_table)) {
346434d611cSSuzuki K Poulose kfree(catu_buf);
347434d611cSSuzuki K Poulose return PTR_ERR(catu_table);
348434d611cSSuzuki K Poulose }
349434d611cSSuzuki K Poulose
350434d611cSSuzuki K Poulose etr_buf->mode = ETR_MODE_CATU;
351434d611cSSuzuki K Poulose etr_buf->private = catu_buf;
352434d611cSSuzuki K Poulose etr_buf->hwaddr = CATU_DEFAULT_INADDR;
353434d611cSSuzuki K Poulose
354434d611cSSuzuki K Poulose catu_buf->catu_table = catu_table;
355434d611cSSuzuki K Poulose /* Get the table base address */
356434d611cSSuzuki K Poulose catu_buf->sladdr = catu_table->table_daddr;
357434d611cSSuzuki K Poulose
358434d611cSSuzuki K Poulose return 0;
359434d611cSSuzuki K Poulose }
360434d611cSSuzuki K Poulose
36166af416dSMian Yousaf Kaukab static const struct etr_buf_operations etr_catu_buf_ops = {
362434d611cSSuzuki K Poulose .alloc = catu_alloc_etr_buf,
363434d611cSSuzuki K Poulose .free = catu_free_etr_buf,
364434d611cSSuzuki K Poulose .sync = catu_sync_etr_buf,
365434d611cSSuzuki K Poulose .get_data = catu_get_data_etr_buf,
366434d611cSSuzuki K Poulose };
367434d611cSSuzuki K Poulose
368fcacb5c1SSuzuki K Poulose static struct attribute *catu_mgmt_attrs[] = {
36908e9fa5fSJames Clark coresight_simple_reg32(devid, CORESIGHT_DEVID),
37008e9fa5fSJames Clark coresight_simple_reg32(control, CATU_CONTROL),
37108e9fa5fSJames Clark coresight_simple_reg32(status, CATU_STATUS),
37208e9fa5fSJames Clark coresight_simple_reg32(mode, CATU_MODE),
37308e9fa5fSJames Clark coresight_simple_reg32(axictrl, CATU_AXICTRL),
37408e9fa5fSJames Clark coresight_simple_reg32(irqen, CATU_IRQEN),
37508e9fa5fSJames Clark coresight_simple_reg64(sladdr, CATU_SLADDRLO, CATU_SLADDRHI),
37608e9fa5fSJames Clark coresight_simple_reg64(inaddr, CATU_INADDRLO, CATU_INADDRHI),
377fcacb5c1SSuzuki K Poulose NULL,
378fcacb5c1SSuzuki K Poulose };
379fcacb5c1SSuzuki K Poulose
380fcacb5c1SSuzuki K Poulose static const struct attribute_group catu_mgmt_group = {
381fcacb5c1SSuzuki K Poulose .attrs = catu_mgmt_attrs,
382fcacb5c1SSuzuki K Poulose .name = "mgmt",
383fcacb5c1SSuzuki K Poulose };
384fcacb5c1SSuzuki K Poulose
385fcacb5c1SSuzuki K Poulose static const struct attribute_group *catu_groups[] = {
386fcacb5c1SSuzuki K Poulose &catu_mgmt_group,
387fcacb5c1SSuzuki K Poulose NULL,
388fcacb5c1SSuzuki K Poulose };
389fcacb5c1SSuzuki K Poulose
390fcacb5c1SSuzuki K Poulose
catu_wait_for_ready(struct catu_drvdata * drvdata)391fcacb5c1SSuzuki K Poulose static inline int catu_wait_for_ready(struct catu_drvdata *drvdata)
392fcacb5c1SSuzuki K Poulose {
39302005282SSuzuki K Poulose struct csdev_access *csa = &drvdata->csdev->access;
39402005282SSuzuki K Poulose
39502005282SSuzuki K Poulose return coresight_timeout(csa, CATU_STATUS, CATU_STATUS_READY, 1);
396fcacb5c1SSuzuki K Poulose }
397fcacb5c1SSuzuki K Poulose
catu_enable_hw(struct catu_drvdata * drvdata,enum cs_mode cs_mode,void * data)398*61486528SJames Clark static int catu_enable_hw(struct catu_drvdata *drvdata, enum cs_mode cs_mode,
399*61486528SJames Clark void *data)
400fcacb5c1SSuzuki K Poulose {
401f92201b1SSuzuki K Poulose int rc;
402434d611cSSuzuki K Poulose u32 control, mode;
403*61486528SJames Clark struct etr_buf *etr_buf = NULL;
404c95e224fSSuzuki K Poulose struct device *dev = &drvdata->csdev->dev;
4058ce00296SSuzuki K Poulose struct coresight_device *csdev = drvdata->csdev;
406*61486528SJames Clark struct coresight_device *etrdev;
407*61486528SJames Clark union coresight_dev_subtype etr_subtype = {
408*61486528SJames Clark .sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM
409*61486528SJames Clark };
410fcacb5c1SSuzuki K Poulose
411fcacb5c1SSuzuki K Poulose if (catu_wait_for_ready(drvdata))
412c95e224fSSuzuki K Poulose dev_warn(dev, "Timeout while waiting for READY\n");
413fcacb5c1SSuzuki K Poulose
414fcacb5c1SSuzuki K Poulose control = catu_read_control(drvdata);
415fcacb5c1SSuzuki K Poulose if (control & BIT(CATU_CONTROL_ENABLE)) {
416c95e224fSSuzuki K Poulose dev_warn(dev, "CATU is already enabled\n");
417fcacb5c1SSuzuki K Poulose return -EBUSY;
418fcacb5c1SSuzuki K Poulose }
419fcacb5c1SSuzuki K Poulose
4208ce00296SSuzuki K Poulose rc = coresight_claim_device_unlocked(csdev);
421f92201b1SSuzuki K Poulose if (rc)
422f92201b1SSuzuki K Poulose return rc;
423f92201b1SSuzuki K Poulose
424*61486528SJames Clark etrdev = coresight_find_input_type(
425*61486528SJames Clark csdev->pdata, CORESIGHT_DEV_TYPE_SINK, etr_subtype);
426*61486528SJames Clark if (etrdev) {
427*61486528SJames Clark etr_buf = tmc_etr_get_buffer(etrdev, cs_mode, data);
428*61486528SJames Clark if (IS_ERR(etr_buf))
429*61486528SJames Clark return PTR_ERR(etr_buf);
430*61486528SJames Clark }
431fcacb5c1SSuzuki K Poulose control |= BIT(CATU_CONTROL_ENABLE);
432434d611cSSuzuki K Poulose
433434d611cSSuzuki K Poulose if (etr_buf && etr_buf->mode == ETR_MODE_CATU) {
434434d611cSSuzuki K Poulose struct catu_etr_buf *catu_buf = etr_buf->private;
435434d611cSSuzuki K Poulose
436434d611cSSuzuki K Poulose mode = CATU_MODE_TRANSLATE;
437434d611cSSuzuki K Poulose catu_write_axictrl(drvdata, CATU_OS_AXICTRL);
438434d611cSSuzuki K Poulose catu_write_sladdr(drvdata, catu_buf->sladdr);
439434d611cSSuzuki K Poulose catu_write_inaddr(drvdata, CATU_DEFAULT_INADDR);
440434d611cSSuzuki K Poulose } else {
441434d611cSSuzuki K Poulose mode = CATU_MODE_PASS_THROUGH;
442434d611cSSuzuki K Poulose catu_write_sladdr(drvdata, 0);
443434d611cSSuzuki K Poulose catu_write_inaddr(drvdata, 0);
444434d611cSSuzuki K Poulose }
445434d611cSSuzuki K Poulose
446434d611cSSuzuki K Poulose catu_write_irqen(drvdata, 0);
447434d611cSSuzuki K Poulose catu_write_mode(drvdata, mode);
448fcacb5c1SSuzuki K Poulose catu_write_control(drvdata, control);
449c95e224fSSuzuki K Poulose dev_dbg(dev, "Enabled in %s mode\n",
450434d611cSSuzuki K Poulose (mode == CATU_MODE_PASS_THROUGH) ?
451434d611cSSuzuki K Poulose "Pass through" :
452434d611cSSuzuki K Poulose "Translate");
453fcacb5c1SSuzuki K Poulose return 0;
454fcacb5c1SSuzuki K Poulose }
455fcacb5c1SSuzuki K Poulose
catu_enable(struct coresight_device * csdev,enum cs_mode mode,void * data)456*61486528SJames Clark static int catu_enable(struct coresight_device *csdev, enum cs_mode mode,
457*61486528SJames Clark void *data)
458fcacb5c1SSuzuki K Poulose {
459fcacb5c1SSuzuki K Poulose int rc;
460fcacb5c1SSuzuki K Poulose struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev);
461fcacb5c1SSuzuki K Poulose
462fcacb5c1SSuzuki K Poulose CS_UNLOCK(catu_drvdata->base);
463*61486528SJames Clark rc = catu_enable_hw(catu_drvdata, mode, data);
464fcacb5c1SSuzuki K Poulose CS_LOCK(catu_drvdata->base);
465fcacb5c1SSuzuki K Poulose return rc;
466fcacb5c1SSuzuki K Poulose }
467fcacb5c1SSuzuki K Poulose
catu_disable_hw(struct catu_drvdata * drvdata)468fcacb5c1SSuzuki K Poulose static int catu_disable_hw(struct catu_drvdata *drvdata)
469fcacb5c1SSuzuki K Poulose {
470fcacb5c1SSuzuki K Poulose int rc = 0;
471c95e224fSSuzuki K Poulose struct device *dev = &drvdata->csdev->dev;
4728ce00296SSuzuki K Poulose struct coresight_device *csdev = drvdata->csdev;
473fcacb5c1SSuzuki K Poulose
474fcacb5c1SSuzuki K Poulose catu_write_control(drvdata, 0);
4758ce00296SSuzuki K Poulose coresight_disclaim_device_unlocked(csdev);
476fcacb5c1SSuzuki K Poulose if (catu_wait_for_ready(drvdata)) {
477c95e224fSSuzuki K Poulose dev_info(dev, "Timeout while waiting for READY\n");
478fcacb5c1SSuzuki K Poulose rc = -EAGAIN;
479fcacb5c1SSuzuki K Poulose }
480fcacb5c1SSuzuki K Poulose
481c95e224fSSuzuki K Poulose dev_dbg(dev, "Disabled\n");
482fcacb5c1SSuzuki K Poulose return rc;
483fcacb5c1SSuzuki K Poulose }
484fcacb5c1SSuzuki K Poulose
catu_disable(struct coresight_device * csdev,void * __unused)485fcacb5c1SSuzuki K Poulose static int catu_disable(struct coresight_device *csdev, void *__unused)
486fcacb5c1SSuzuki K Poulose {
487fcacb5c1SSuzuki K Poulose int rc;
488fcacb5c1SSuzuki K Poulose struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev);
489fcacb5c1SSuzuki K Poulose
490fcacb5c1SSuzuki K Poulose CS_UNLOCK(catu_drvdata->base);
491fcacb5c1SSuzuki K Poulose rc = catu_disable_hw(catu_drvdata);
492fcacb5c1SSuzuki K Poulose CS_LOCK(catu_drvdata->base);
493fcacb5c1SSuzuki K Poulose return rc;
494fcacb5c1SSuzuki K Poulose }
495fcacb5c1SSuzuki K Poulose
49661810404SYueHaibing static const struct coresight_ops_helper catu_helper_ops = {
497fcacb5c1SSuzuki K Poulose .enable = catu_enable,
498fcacb5c1SSuzuki K Poulose .disable = catu_disable,
499fcacb5c1SSuzuki K Poulose };
500fcacb5c1SSuzuki K Poulose
50161810404SYueHaibing static const struct coresight_ops catu_ops = {
502fcacb5c1SSuzuki K Poulose .helper_ops = &catu_helper_ops,
503fcacb5c1SSuzuki K Poulose };
504fcacb5c1SSuzuki K Poulose
catu_probe(struct amba_device * adev,const struct amba_id * id)505fcacb5c1SSuzuki K Poulose static int catu_probe(struct amba_device *adev, const struct amba_id *id)
506fcacb5c1SSuzuki K Poulose {
507fcacb5c1SSuzuki K Poulose int ret = 0;
508fcacb5c1SSuzuki K Poulose u32 dma_mask;
509fcacb5c1SSuzuki K Poulose struct catu_drvdata *drvdata;
510fcacb5c1SSuzuki K Poulose struct coresight_desc catu_desc;
511fcacb5c1SSuzuki K Poulose struct coresight_platform_data *pdata = NULL;
512fcacb5c1SSuzuki K Poulose struct device *dev = &adev->dev;
513fcacb5c1SSuzuki K Poulose void __iomem *base;
514fcacb5c1SSuzuki K Poulose
5150f5f9b6bSSuzuki K Poulose catu_desc.name = coresight_alloc_device_name(&catu_devs, dev);
5160f5f9b6bSSuzuki K Poulose if (!catu_desc.name)
5170f5f9b6bSSuzuki K Poulose return -ENOMEM;
5180f5f9b6bSSuzuki K Poulose
519fcacb5c1SSuzuki K Poulose drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
520fcacb5c1SSuzuki K Poulose if (!drvdata) {
521fcacb5c1SSuzuki K Poulose ret = -ENOMEM;
522fcacb5c1SSuzuki K Poulose goto out;
523fcacb5c1SSuzuki K Poulose }
524fcacb5c1SSuzuki K Poulose
525fcacb5c1SSuzuki K Poulose dev_set_drvdata(dev, drvdata);
526fcacb5c1SSuzuki K Poulose base = devm_ioremap_resource(dev, &adev->res);
527fcacb5c1SSuzuki K Poulose if (IS_ERR(base)) {
528fcacb5c1SSuzuki K Poulose ret = PTR_ERR(base);
529fcacb5c1SSuzuki K Poulose goto out;
530fcacb5c1SSuzuki K Poulose }
531fcacb5c1SSuzuki K Poulose
532fcacb5c1SSuzuki K Poulose /* Setup dma mask for the device */
533fcacb5c1SSuzuki K Poulose dma_mask = readl_relaxed(base + CORESIGHT_DEVID) & 0x3f;
534fcacb5c1SSuzuki K Poulose switch (dma_mask) {
535fcacb5c1SSuzuki K Poulose case 32:
536fcacb5c1SSuzuki K Poulose case 40:
537fcacb5c1SSuzuki K Poulose case 44:
538fcacb5c1SSuzuki K Poulose case 48:
539fcacb5c1SSuzuki K Poulose case 52:
540fcacb5c1SSuzuki K Poulose case 56:
541fcacb5c1SSuzuki K Poulose case 64:
542fcacb5c1SSuzuki K Poulose break;
543fcacb5c1SSuzuki K Poulose default:
544fcacb5c1SSuzuki K Poulose /* Default to the 40bits as supported by TMC-ETR */
545fcacb5c1SSuzuki K Poulose dma_mask = 40;
546fcacb5c1SSuzuki K Poulose }
547fcacb5c1SSuzuki K Poulose ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_mask));
548fcacb5c1SSuzuki K Poulose if (ret)
549fcacb5c1SSuzuki K Poulose goto out;
550fcacb5c1SSuzuki K Poulose
551af7cfd0fSSuzuki K Poulose pdata = coresight_get_platform_data(dev);
552af7cfd0fSSuzuki K Poulose if (IS_ERR(pdata)) {
553af7cfd0fSSuzuki K Poulose ret = PTR_ERR(pdata);
554af7cfd0fSSuzuki K Poulose goto out;
555af7cfd0fSSuzuki K Poulose }
556af7cfd0fSSuzuki K Poulose dev->platform_data = pdata;
557af7cfd0fSSuzuki K Poulose
558fcacb5c1SSuzuki K Poulose drvdata->base = base;
5596e736c60SSuzuki K Poulose catu_desc.access = CSDEV_ACCESS_IOMEM(base);
560fcacb5c1SSuzuki K Poulose catu_desc.pdata = pdata;
561fcacb5c1SSuzuki K Poulose catu_desc.dev = dev;
562fcacb5c1SSuzuki K Poulose catu_desc.groups = catu_groups;
563fcacb5c1SSuzuki K Poulose catu_desc.type = CORESIGHT_DEV_TYPE_HELPER;
564fcacb5c1SSuzuki K Poulose catu_desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_CATU;
565fcacb5c1SSuzuki K Poulose catu_desc.ops = &catu_ops;
5662ede79a6SSuzuki K Poulose
567fcacb5c1SSuzuki K Poulose drvdata->csdev = coresight_register(&catu_desc);
568fcacb5c1SSuzuki K Poulose if (IS_ERR(drvdata->csdev))
569fcacb5c1SSuzuki K Poulose ret = PTR_ERR(drvdata->csdev);
5702390d458SSuzuki K Poulose else
571fcacb5c1SSuzuki K Poulose pm_runtime_put(&adev->dev);
5722390d458SSuzuki K Poulose out:
573fcacb5c1SSuzuki K Poulose return ret;
574fcacb5c1SSuzuki K Poulose }
575fcacb5c1SSuzuki K Poulose
catu_remove(struct amba_device * adev)5763fd269e7SUwe Kleine-König static void catu_remove(struct amba_device *adev)
577a114dbeaSTingwei Zhang {
578a114dbeaSTingwei Zhang struct catu_drvdata *drvdata = dev_get_drvdata(&adev->dev);
579a114dbeaSTingwei Zhang
580a114dbeaSTingwei Zhang coresight_unregister(drvdata->csdev);
581a114dbeaSTingwei Zhang }
582a114dbeaSTingwei Zhang
583fcacb5c1SSuzuki K Poulose static struct amba_id catu_ids[] = {
5849cfb5563SSai Prakash Ranjan CS_AMBA_ID(0x000bb9ee),
585fcacb5c1SSuzuki K Poulose {},
586fcacb5c1SSuzuki K Poulose };
587fcacb5c1SSuzuki K Poulose
588a114dbeaSTingwei Zhang MODULE_DEVICE_TABLE(amba, catu_ids);
589a114dbeaSTingwei Zhang
590fcacb5c1SSuzuki K Poulose static struct amba_driver catu_driver = {
591fcacb5c1SSuzuki K Poulose .drv = {
592fcacb5c1SSuzuki K Poulose .name = "coresight-catu",
593fcacb5c1SSuzuki K Poulose .owner = THIS_MODULE,
594fcacb5c1SSuzuki K Poulose .suppress_bind_attrs = true,
595fcacb5c1SSuzuki K Poulose },
596fcacb5c1SSuzuki K Poulose .probe = catu_probe,
597a114dbeaSTingwei Zhang .remove = catu_remove,
598fcacb5c1SSuzuki K Poulose .id_table = catu_ids,
599fcacb5c1SSuzuki K Poulose };
600fcacb5c1SSuzuki K Poulose
catu_init(void)60166af416dSMian Yousaf Kaukab static int __init catu_init(void)
60266af416dSMian Yousaf Kaukab {
60366af416dSMian Yousaf Kaukab int ret;
60466af416dSMian Yousaf Kaukab
60566af416dSMian Yousaf Kaukab ret = amba_driver_register(&catu_driver);
60666af416dSMian Yousaf Kaukab if (ret)
60766af416dSMian Yousaf Kaukab pr_info("Error registering catu driver\n");
60866af416dSMian Yousaf Kaukab tmc_etr_set_catu_ops(&etr_catu_buf_ops);
60966af416dSMian Yousaf Kaukab return ret;
61066af416dSMian Yousaf Kaukab }
61166af416dSMian Yousaf Kaukab
catu_exit(void)61266af416dSMian Yousaf Kaukab static void __exit catu_exit(void)
61366af416dSMian Yousaf Kaukab {
61466af416dSMian Yousaf Kaukab tmc_etr_remove_catu_ops();
61566af416dSMian Yousaf Kaukab amba_driver_unregister(&catu_driver);
61666af416dSMian Yousaf Kaukab }
61766af416dSMian Yousaf Kaukab
61866af416dSMian Yousaf Kaukab module_init(catu_init);
61966af416dSMian Yousaf Kaukab module_exit(catu_exit);
620a114dbeaSTingwei Zhang
621a114dbeaSTingwei Zhang MODULE_AUTHOR("Suzuki K Poulose <suzuki.poulose@arm.com>");
622a114dbeaSTingwei Zhang MODULE_DESCRIPTION("Arm CoreSight Address Translation Unit (CATU) Driver");
623a114dbeaSTingwei Zhang MODULE_LICENSE("GPL v2");
624