1 /*
2  * Copyright (c) 2023 Intel Corporation
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "ish_dma.h"
8 
9 static int dma_init_called; /* If ish_dma_init is called */
10 
dma_poll(uint32_t addr,uint32_t expected,uint32_t mask)11 static int dma_poll(uint32_t addr, uint32_t expected, uint32_t mask)
12 {
13 	int retval = -1;
14 	uint32_t counter = 0;
15 
16 	/*
17 	 * The timeout is approximately 2.2 seconds according to
18 	 * value of UINT32_MAX, 120MHZ ISH clock frequency and
19 	 * instruction count which is around 4.
20 	 */
21 	while (counter < (UINT32_MAX / 64)) {
22 		/* test condition */
23 		if ((read32(addr) & mask) == expected) {
24 			retval = DMA_RC_OK;
25 			break;
26 		}
27 		counter++;
28 	}
29 
30 	return retval;
31 }
32 
interrupt_lock(void)33 static inline uint32_t interrupt_lock(void)
34 {
35 	uint32_t eflags = 0;
36 
37 	__asm__ volatile("pushfl;" /* save eflag value */
38 			 "popl  %0;"
39 			 "cli;"
40 			 : "=r"(eflags)); /* shut off interrupts */
41 	return eflags;
42 }
43 
interrupt_unlock(uint32_t eflags)44 static inline void interrupt_unlock(uint32_t eflags)
45 {
46 	__asm__ volatile("pushl  %0;" /* restore elfag values */
47 			 "popfl;"
48 			 :
49 			 : "r"(eflags));
50 }
51 
dma_configure_psize(void)52 void dma_configure_psize(void)
53 {
54 	/* Give chan0 512 bytes for high performance, and chan1 128 bytes. */
55 	write32(DMA_PSIZE_01, (DMA_PSIZE_UPDATE |
56 		       (DMA_PSIZE_CHAN1_SIZE << DMA_PSIZE_CHAN1_OFFSET) |
57 		       (DMA_PSIZE_CHAN0_SIZE << DMA_PSIZE_CHAN0_OFFSET)));
58 }
59 
ish_dma_init(void)60 void ish_dma_init(void)
61 {
62 	uint32_t uma_msb;
63 
64 	/* configure DMA partition size */
65 	dma_configure_psize();
66 
67 	/* set DRAM address 32 MSB for DMA transactions on UMA */
68 	uma_msb = read32(IPC_UMA_RANGE_LOWER_1);
69 	ish_dma_set_msb(PAGING_CHAN, uma_msb, uma_msb);
70 
71 	dma_init_called = 1;
72 }
73 
ish_dma_copy(uint32_t chan,uint32_t dst,uint32_t src,uint32_t length,enum dma_mode mode)74 int ish_dma_copy(uint32_t chan, uint32_t dst, uint32_t src, uint32_t length,
75 		 enum dma_mode mode)
76 {
77 	uint32_t chan_reg = DMA_REG_BASE + (DMA_CH_REGS_SIZE * chan);
78 	int rc = DMA_RC_OK;
79 	uint32_t eflags;
80 	uint32_t chunk;
81 
82 	__asm__ volatile("\twbinvd\n"); /* Flush cache before dma start */
83 
84 	/* Bringup VNN power rail for accessing SoC fabric */
85 	write32(PMU_VNN_REQ, (1 << VNN_ID_DMA(chan)));
86 	while (!(read32(PMU_VNN_REQ_ACK) & PMU_VNN_REQ_ACK_STATUS))
87 		continue;
88 
89 	/*
90 	 * shut off interrupts to assure no simultanious
91 	 * access to DMA registers
92 	 */
93 	eflags = interrupt_lock();
94 
95 	write32(MISC_CHID_CFG_REG, chan); /* Set channel to configure */
96 
97 	mode |= NON_SNOOP;
98 	write32(MISC_DMA_CTL_REG(chan), mode); /* Set transfer direction */
99 
100 	write32(DMA_CFG_REG, DMA_ENABLE);  /* Enable DMA module */
101 	write32(DMA_LLP(chan_reg), 0);     /* Linked lists are not used */
102 	write32(DMA_CTL_LOW(chan_reg),
103 		0 /* Set transfer parameters */ |
104 		(DMA_CTL_TT_FC_M2M_DMAC << DMA_CTL_TT_FC_SHIFT) |
105 		(DMA_CTL_ADDR_INC << DMA_CTL_SINC_SHIFT) |
106 		(DMA_CTL_ADDR_INC << DMA_CTL_DINC_SHIFT) |
107 		(SRC_TR_WIDTH << DMA_CTL_SRC_TR_WIDTH_SHIFT) |
108 		(DEST_TR_WIDTH << DMA_CTL_DST_TR_WIDTH_SHIFT) |
109 		(SRC_BURST_SIZE << DMA_CTL_SRC_MSIZE_SHIFT) |
110 		(DEST_BURST_SIZE << DMA_CTL_DEST_MSIZE_SHIFT));
111 
112 	interrupt_unlock(eflags);
113 	while (length) {
114 		chunk = (length > DMA_MAX_BLOCK_SIZE) ? DMA_MAX_BLOCK_SIZE
115 						      : length;
116 
117 		if (rc != DMA_RC_OK)
118 			break;
119 
120 		eflags = interrupt_lock();
121 		write32(MISC_CHID_CFG_REG, chan); /* Set channel to configure */
122 		write32(DMA_CTL_HIGH(chan_reg), chunk);	/* Set number of bytes to transfer */
123 		write32(DMA_DAR(chan_reg), dst); /* Destination address */
124 		write32(DMA_SAR(chan_reg), src); /* Source address */
125 		write32(DMA_EN_REG, DMA_CH_EN_BIT(chan) |
126 			     DMA_CH_EN_WE_BIT(chan)); /* Enable the channel */
127 		interrupt_unlock(eflags);
128 
129 		rc = ish_wait_for_dma_done(
130 			chan); /* Wait for trans completion */
131 
132 		dst += chunk;
133 		src += chunk;
134 		length -= chunk;
135 	}
136 
137 	/* Mark the DMA VNN power rail as no longer needed */
138 	write32(PMU_VNN_REQ, (1 << VNN_ID_DMA(chan)));
139 	return rc;
140 }
141 
ish_dma_disable(void)142 void ish_dma_disable(void)
143 {
144 	uint32_t channel;
145 	uint32_t counter;
146 
147 	/* Disable DMA on per-channel basis. */
148 	for (channel = 0; channel <= DMA_MAX_CHANNEL; channel++) {
149 		write32(MISC_CHID_CFG_REG, channel);
150 		if (read32(DMA_EN_REG) & DMA_CH_EN_BIT(channel)) {
151 			/* Write 0 to channel enable bit ... */
152 			write32(DMA_EN_REG, DMA_CH_EN_WE_BIT(channel));
153 
154 			/* Wait till it shuts up. */
155 			counter = 0;
156 			while ((read32(DMA_EN_REG) & DMA_CH_EN_BIT(channel)) &&
157 			       counter < (UINT32_MAX / 64))
158 				counter++;
159 		}
160 	}
161 	write32(DMA_CLR_ERR_REG, 0xFFFFFFFF);
162 	write32(DMA_CLR_BLOCK_REG, 0xFFFFFFFF);
163 
164 	write32(DMA_CFG_REG, 0); /* Disable DMA module */
165 }
166 
ish_wait_for_dma_done(uint32_t ch)167 int ish_wait_for_dma_done(uint32_t ch)
168 {
169 	return dma_poll(DMA_EN_REG_ADDR, 0, DMA_CH_EN_BIT(ch));
170 }
171 
ish_dma_set_msb(uint32_t chan,uint32_t dst_msb,uint32_t src_msb)172 void ish_dma_set_msb(uint32_t chan, uint32_t dst_msb, uint32_t src_msb)
173 {
174 	uint32_t eflags = interrupt_lock();
175 
176 	write32(MISC_CHID_CFG_REG, chan); /* Set channel to configure */
177 	write32(MISC_SRC_FILLIN_DMA(chan), src_msb);
178 	write32(MISC_DST_FILLIN_DMA(chan), dst_msb);
179 	interrupt_unlock(eflags);
180 }
181