blob: 56490214544bd8d95d03820eddbd9d6fb86277bb [file] [log] [blame]
Naveen Ramarajcc4ec152012-05-14 09:55:29 -07001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/mm.h>
17#include <linux/rbtree.h>
18#include <linux/genalloc.h>
19#include <linux/of.h>
20#include <linux/io.h>
21#include <linux/platform_device.h>
22#include <linux/debugfs.h>
23#include <linux/seq_file.h>
24#include <linux/delay.h>
25#include <linux/interrupt.h>
26#include <linux/wait.h>
27#include <linux/sched.h>
28#include <mach/ocmem_priv.h>
29
30#define RDM_MAX_ENTRIES 32
31#define RDM_MAX_CLIENTS 2
32
33/* Data Mover Parameters */
34#define DM_BLOCK_128 0x0
35#define DM_BLOCK_256 0x1
36#define DM_BR_ID_LPASS 0x0
37#define DM_BR_ID_GPS 0x1
38
39#define DM_INTR_CLR (0x8)
40#define DM_INTR_MASK (0xC)
41#define DM_GEN_STATUS (0x10)
42#define DM_STATUS (0x14)
43#define DM_CTRL (0x1000)
44#define DM_TBL_BASE (0x1010)
45#define DM_TBL_IDX(x) ((x) * 0x18)
46#define DM_TBL_n(x) (DM_TBL_BASE + (DM_TBL_IDX(x)))
47#define DM_TBL_n_offset(x) DM_TBL_n(x)
48#define DM_TBL_n_size(x) (DM_TBL_n(x)+0x4)
49#define DM_TBL_n_paddr(x) (DM_TBL_n(x)+0x8)
50#define DM_TBL_n_ctrl(x) (DM_TBL_n(x)+0x10)
51
52#define BR_CTRL (0x0)
53#define BR_CLIENT_BASE (0x4)
54#define BR_CLIENT_n_IDX(x) ((x) * 0x4)
55#define BR_CLIENT_n_ctrl(x) (BR_CLIENT_BASE + (BR_CLIENT_n_IDX(x)))
56#define BR_STATUS (0x14)
57/* 16 entries per client are supported */
58/* Use entries 0 - 15 for client0 */
59#define BR_CLIENT0_MASK (0x1000)
60/* Use entries 16- 31 for client1 */
61#define BR_CLIENT1_MASK (0x2010)
62
63#define BR_TBL_BASE (0x40)
64#define BR_TBL_IDX(x) ((x) * 0x18)
65#define BR_TBL_n(x) (BR_TBL_BASE + (BR_TBL_IDX(x)))
66#define BR_TBL_n_offset(x) BR_TBL_n(x)
67#define BR_TBL_n_size(x) (BR_TBL_n(x)+0x4)
68#define BR_TBL_n_paddr(x) (BR_TBL_n(x)+0x8)
69#define BR_TBL_n_ctrl(x) (BR_TBL_n(x)+0x10)
70
71/* Constants and Shifts */
72#define BR_TBL_ENTRY_ENABLE 0x1
73#define BR_TBL_START 0x0
74#define BR_TBL_END 0x8
75#define BR_RW_SHIFT 0x2
76
77#define DM_TBL_START 0x10
78#define DM_TBL_END 0x18
79#define DM_CLIENT_SHIFT 0x8
80#define DM_BR_ID_SHIFT 0x4
81#define DM_BR_BLK_SHIFT 0x1
82#define DM_DIR_SHIFT 0x0
83
84#define DM_DONE 0x1
85#define DM_INTR_ENABLE 0x0
86#define DM_INTR_DISABLE 0x1
87
88static void *br_base;
89static void *dm_base;
90
91static atomic_t dm_pending;
92static wait_queue_head_t dm_wq;
93/* Shadow tables for debug purposes */
94struct ocmem_br_table {
95 unsigned int offset;
96 unsigned int size;
97 unsigned int ddr_low;
98 unsigned int ddr_high;
99 unsigned int ctrl;
100} br_table[RDM_MAX_ENTRIES];
101
102/* DM Table replicates an entire BR table */
103/* Note: There are more than 1 BRs in the system */
104struct ocmem_dm_table {
105 unsigned int offset;
106 unsigned int size;
107 unsigned int ddr_low;
108 unsigned int ddr_high;
109 unsigned int ctrl;
110} dm_table[RDM_MAX_ENTRIES];
111
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700112static inline int client_ctrl_id(int id)
113{
114 return (id == OCMEM_SENSORS) ? 1 : 0;
115}
116
117static inline int client_slot_start(int id)
118{
119
120 return client_ctrl_id(id) * 16;
121}
122
123static irqreturn_t ocmem_dm_irq_handler(int irq, void *dev_id)
124{
125 atomic_set(&dm_pending, 0);
126 ocmem_write(DM_INTR_DISABLE, dm_base + DM_INTR_CLR);
127 wake_up_interruptible(&dm_wq);
128 return IRQ_HANDLED;
129}
130
131/* Lock during transfers */
132int ocmem_rdm_transfer(int id, struct ocmem_map_list *clist,
133 unsigned long start, int direction)
134{
135 int num_chunks = clist->num_chunks;
136 int slot = client_slot_start(id);
137 int table_start = 0;
138 int table_end = 0;
139 int br_ctrl = 0;
140 int br_id = 0;
141 int dm_ctrl = 0;
142 int i = 0;
143 int j = 0;
144 int status = 0;
145
146 for (i = 0, j = slot; i < num_chunks; i++, j++) {
147
148 struct ocmem_chunk *chunk = &clist->chunks[i];
149 int sz = chunk->size;
150 int paddr = chunk->ddr_paddr;
151 int tbl_n_ctrl = 0;
152
153 tbl_n_ctrl |= BR_TBL_ENTRY_ENABLE;
154 if (chunk->ro)
155 tbl_n_ctrl |= (1 << BR_RW_SHIFT);
156
157 /* Table Entry n of BR and DM */
158 ocmem_write(start, br_base + BR_TBL_n_offset(j));
159 ocmem_write(sz, br_base + BR_TBL_n_size(j));
160 ocmem_write(paddr, br_base + BR_TBL_n_paddr(j));
161 ocmem_write(tbl_n_ctrl, br_base + BR_TBL_n_ctrl(j));
162
163 ocmem_write(start, dm_base + DM_TBL_n_offset(j));
164 ocmem_write(sz, dm_base + DM_TBL_n_size(j));
165 ocmem_write(paddr, dm_base + DM_TBL_n_paddr(j));
166 ocmem_write(tbl_n_ctrl, dm_base + DM_TBL_n_ctrl(j));
167
168 start += sz;
169 }
170
171 br_id = client_ctrl_id(id);
172 table_start = slot;
173 table_end = slot + num_chunks - 1;
174 br_ctrl |= (table_start << BR_TBL_START);
175 br_ctrl |= (table_end << BR_TBL_END);
176
177 ocmem_write(br_ctrl, (br_base + BR_CLIENT_n_ctrl(br_id)));
178 /* Enable BR */
179 ocmem_write(0x1, br_base + BR_CTRL);
180
181 /* Compute DM Control Value */
182 dm_ctrl |= (table_start << DM_TBL_START);
183 dm_ctrl |= (table_end << DM_TBL_END);
184
185 dm_ctrl |= (DM_BR_ID_LPASS << DM_BR_ID_SHIFT);
186 dm_ctrl |= (DM_BLOCK_256 << DM_BR_BLK_SHIFT);
187 dm_ctrl |= (direction << DM_DIR_SHIFT);
188
189 status = ocmem_read(dm_base + DM_STATUS);
190 pr_debug("Transfer status before %x\n", status);
191 atomic_set(&dm_pending, 1);
192 /* Trigger DM */
193 ocmem_write(dm_ctrl, dm_base + DM_CTRL);
194 pr_debug("ocmem: rdm: dm_ctrl %x br_ctrl %x\n", dm_ctrl, br_ctrl);
195
196 wait_event_interruptible(dm_wq,
197 atomic_read(&dm_pending) == 0);
198
199 return 0;
200}
201
202int ocmem_rdm_init(struct platform_device *pdev)
203{
204
205 struct ocmem_plat_data *pdata = NULL;
206 int rc = 0;
207
208 pdata = platform_get_drvdata(pdev);
209
210 br_base = pdata->br_base;
211 dm_base = pdata->dm_base;
212
213 rc = devm_request_irq(&pdev->dev, pdata->dm_irq, ocmem_dm_irq_handler,
214 IRQF_TRIGGER_RISING, "ocmem_dm_irq", pdata);
215
216 if (rc) {
217 dev_err(&pdev->dev, "Failed to request dm irq");
218 return -EINVAL;
219 }
220
221 init_waitqueue_head(&dm_wq);
222 /* enable dm interrupts */
223 ocmem_write(DM_INTR_ENABLE, dm_base + DM_INTR_MASK);
224 return 0;
225}