1 /*
2 * Copyright (c) 2022 Winner Microelectronics Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <string.h>
17 #include "wm_regs.h"
18 #include "wm_dma.h"
19 #include "wm_psram.h"
20
21 /* Nonzero if either X or Y is not aligned on a "long" boundary. */
22 #define UNALIGNED(X, Y) \
23 (((uint32_t)(X) & (sizeof (uint32_t) - 1)) | ((uint32_t)(Y) & (sizeof (uint32_t) - 1)))
24 /* How many bytes are copied each iteration of the 4X unrolled loop. */
25 #define BIGBLOCKSIZE (sizeof (uint32_t) << 2)
26 /* Threshhold for punting to the byte copier. */
27 #define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE)
28
29 volatile static uint32_t dma_rx_tx_done = 0;
30 static uint32_t psram_channel = 0;
31
wm_psram_dma_go(uint8_t ch)32 static void wm_psram_dma_go(uint8_t ch)
33 {
34 DMA_CHNLCTRL_REG(ch) = DMA_CHNL_CTRL_CHNL_ON;
35 dma_rx_tx_done = 0;
36 }
37
wm_psram_dma_stop(uint8_t ch)38 static void wm_psram_dma_stop(uint8_t ch)
39 {
40 if (DMA_CHNLCTRL_REG(ch) & DMA_CHNL_CTRL_CHNL_ON) {
41 DMA_CHNLCTRL_REG(ch) |= DMA_CHNL_CTRL_CHNL_OFF;
42
43 while (DMA_CHNLCTRL_REG(ch) & DMA_CHNL_CTRL_CHNL_ON);
44 }
45 }
46
wm_psram_dma_init(uint8_t ch,uint32_t count,void * src,void * dst)47 static void wm_psram_dma_init(uint8_t ch, uint32_t count, void * src, void *dst)
48 {
49 DMA_INTMASK_REG &= ~(0x02<<(ch*2));
50 DMA_SRCADDR_REG(ch) = (uint32_t)src;
51 DMA_DESTADDR_REG(ch) = (uint32_t)dst;
52
53 DMA_CTRL_REG(ch) = DMA_CTRL_SRC_ADDR_INC|DMA_CTRL_DEST_ADDR_INC | DMA_CTRL_DATA_SIZE_WORD | DMA_CTRL_BURST_SIZE1;
54 DMA_MODE_REG(ch) = 0;
55 DMA_CTRL_REG(ch) &= ~0xFFFF00;
56 DMA_CTRL_REG(ch) |= (count<<8);
57 }
58
psram_DMA_Channel0_IRQHandler(void)59 void psram_DMA_Channel0_IRQHandler(void)
60 {
61 tls_reg_write32(HR_DMA_INT_SRC, 0x02);
62 dma_rx_tx_done += 1;
63 }
64
psram_init(psram_mode_t mode)65 void psram_init(psram_mode_t mode)
66 {
67 volatile unsigned int value = 0x600;
68
69 value |= 2<<4;
70
71 if (mode == PSRAM_QPI) {
72 value |= 0x03;
73 }
74
75 /* reset psram */
76 value |= 0x01;
77 tls_reg_write32(HR_PSRAM_CTRL_ADDR, value);
78 do {
79 value = tls_reg_read32(HR_PSRAM_CTRL_ADDR);
80 }while (value&0x01);
81
82 psram_channel = tls_dma_request(0, 0);
83 tls_dma_irq_register(psram_channel, psram_DMA_Channel0_IRQHandler, NULL, TLS_DMA_IRQ_TRANSFER_DONE);
84 }
85
memcpy_dma(unsigned char * dst,unsigned char * src,int num)86 int memcpy_dma(unsigned char *dst, unsigned char *src, int num)
87 {
88 int offset = 0;
89 int Num = num;
90 unsigned char *psram_access_start = src;
91
92 int left_bytes = Num&0x03;
93 int dw_length = (Num&(~0x03))>>2;
94
95 if (!TOO_SMALL(Num) && !UNALIGNED (src, dst)) {
96 if (dw_length) {
97 wm_psram_dma_stop(psram_channel);
98 wm_psram_dma_init(psram_channel, dw_length*4, src, dst);
99 wm_psram_dma_go(psram_channel);
100 while (dma_rx_tx_done == 0);
101 offset += dw_length *4;
102 psram_access_start += dw_length *4;
103 } else {
104 while (dw_length--) {
105 M32((dst+offset)) = M32(psram_access_start);
106 psram_access_start += 4;
107 offset+=4;
108 }
109 }
110 while (left_bytes--) {
111 M8((dst+offset)) = M8(psram_access_start);
112 psram_access_start += 1;
113 offset+=1;
114 }
115 } else {
116 while (Num--) {
117 M8(dst++) = M8(psram_access_start++);
118 offset++;
119 }
120 }
121 return offset;
122 }