blob: c1b812a6a4badbb6aabb147ea4fc97f8c5ec91c3 [file] [log] [blame]
Dhaval Patel020f7e122016-11-15 14:39:18 -08001/* Copyright (c) 2016-2017, The Linux Foundation. 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
14#define pr_fmt(fmt) "[sde_rsc:%s:%d]: " fmt, __func__, __LINE__
15
16#include <linux/kernel.h>
17#include <linux/debugfs.h>
18#include <linux/of.h>
19#include <linux/string.h>
20#include <linux/of_address.h>
21#include <linux/component.h>
22#include <linux/slab.h>
23#include <linux/mutex.h>
24#include <linux/of_platform.h>
25#include <linux/module.h>
26
27#include <soc/qcom/rpmh.h>
28#include <drm/drmP.h>
29#include <drm/drm_irq.h>
Dhaval Patel49ef6d72017-03-26 09:35:53 -070030#include "sde_rsc_priv.h"
Dhaval Patel020f7e122016-11-15 14:39:18 -080031
32/* this time is ~0.02ms */
33#define RSC_BACKOFF_TIME_NS 20000
34
35/* next two values should be same based on doc */
36
37/* this time is ~0.2ms */
38#define RSC_MODE_THRESHOLD_TIME_IN_NS 200000
39/* this time is ~0.2ms */
40#define RSC_TIME_SLOT_0_NS 200000
41
42#define DEFAULT_PANEL_FPS 60
43#define DEFAULT_PANEL_JITTER 5
44#define DEFAULT_PANEL_PREFILL_LINES 16
45#define DEFAULT_PANEL_VTOTAL (480 + DEFAULT_PANEL_PREFILL_LINES)
46#define TICKS_IN_NANO_SECOND 1000000000
47
48#define MAX_BUFFER_SIZE 256
49
50#define TRY_CMD_MODE_SWITCH 0xFFFF
Dhaval Patela65b0f12017-03-16 00:36:55 -070051#define TRY_CLK_MODE_SWITCH 0xFFFE
52#define STATE_UPDATE_NOT_ALLOWED 0xFFFD
Dhaval Patel020f7e122016-11-15 14:39:18 -080053
54static struct sde_rsc_priv *rsc_prv_list[MAX_RSC_COUNT];
55
56/**
57 * sde_rsc_client_create() - create the client for sde rsc.
58 * Different displays like DSI, HDMI, DP, WB, etc should call this
59 * api to register their vote for rpmh. They still need to vote for
60 * power handle to get the clocks.
61
62 * @rsc_index: A client will be created on this RSC. As of now only
63 * SDE_RSC_INDEX is valid rsc index.
64 * @name: Caller needs to provide some valid string to identify
65 * the client. "primary", "dp", "hdmi" are suggested name.
66 * @is_primary: Caller needs to provide information if client is primary
67 * or not. Primary client votes will be redirected to
68 * display rsc.
69 *
70 * Return: client node pointer.
71 */
72struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index, char *client_name,
73 bool is_primary_client)
74{
75 struct sde_rsc_client *client;
76 struct sde_rsc_priv *rsc;
77
78 if (!client_name) {
79 pr_err("client name is null- not supported\n");
80 return ERR_PTR(-EINVAL);
81 } else if (rsc_index >= MAX_RSC_COUNT) {
82 pr_err("invalid rsc index\n");
83 return ERR_PTR(-EINVAL);
84 } else if (!rsc_prv_list[rsc_index]) {
85 pr_err("rsc not probed yet or not available\n");
86 return ERR_PTR(-EINVAL);
87 }
88
89 rsc = rsc_prv_list[rsc_index];
90 client = kzalloc(sizeof(struct sde_rsc_client), GFP_KERNEL);
91 if (!client)
92 return ERR_PTR(-ENOMEM);
93
94 mutex_lock(&rsc->client_lock);
95 strlcpy(client->name, client_name, MAX_RSC_CLIENT_NAME_LEN);
96 client->current_state = SDE_RSC_IDLE_STATE;
97 client->rsc_index = rsc_index;
98 if (is_primary_client)
99 rsc->primary_client = client;
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800100 pr_debug("client %s rsc index:%d primary:%d\n", client_name,
101 rsc_index, is_primary_client);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800102
103 list_add(&client->list, &rsc->client_list);
104 mutex_unlock(&rsc->client_lock);
105
106 return client;
107}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700108EXPORT_SYMBOL(sde_rsc_client_create);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800109
110/**
111 * sde_rsc_client_destroy() - Destroy the sde rsc client.
112 *
113 * @client: Client pointer provided by sde_rsc_client_create().
114 *
115 * Return: none
116 */
117void sde_rsc_client_destroy(struct sde_rsc_client *client)
118{
119 struct sde_rsc_priv *rsc;
120
121 if (!client) {
122 pr_debug("invalid client\n");
123 goto end;
124 } else if (client->rsc_index >= MAX_RSC_COUNT) {
125 pr_err("invalid rsc index\n");
126 goto end;
127 }
128
129 pr_debug("client %s destroyed\n", client->name);
130 rsc = rsc_prv_list[client->rsc_index];
131 if (!rsc)
132 goto end;
133
134 mutex_lock(&rsc->client_lock);
135 if (client->current_state != SDE_RSC_IDLE_STATE)
136 sde_rsc_client_state_update(client, SDE_RSC_IDLE_STATE,
137 NULL, -1);
138 list_del_init(&client->list);
139 mutex_unlock(&rsc->client_lock);
140
141 kfree(client);
142end:
143 return;
144}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700145EXPORT_SYMBOL(sde_rsc_client_destroy);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800146
Dhaval Patel031b4152017-03-16 13:03:18 -0700147struct sde_rsc_event *sde_rsc_register_event(int rsc_index, uint32_t event_type,
148 void (*cb_func)(uint32_t event_type, void *usr), void *usr)
149{
150 struct sde_rsc_event *evt;
151 struct sde_rsc_priv *rsc;
152
153 if (rsc_index >= MAX_RSC_COUNT) {
154 pr_err("invalid rsc index:%d\n", rsc_index);
155 return ERR_PTR(-EINVAL);
156 } else if (!rsc_prv_list[rsc_index]) {
157 pr_err("rsc idx:%d not probed yet or not available\n",
158 rsc_index);
159 return ERR_PTR(-EINVAL);
160 } else if (!cb_func || !event_type) {
161 pr_err("no event or cb func\n");
162 return ERR_PTR(-EINVAL);
163 }
164
165 rsc = rsc_prv_list[rsc_index];
166 evt = kzalloc(sizeof(struct sde_rsc_event), GFP_KERNEL);
167 if (!evt)
168 return ERR_PTR(-ENOMEM);
169
170 evt->event_type = event_type;
171 evt->rsc_index = rsc_index;
172 evt->usr = usr;
173 evt->cb_func = cb_func;
174 pr_debug("event register type:%d rsc index:%d\n",
175 event_type, rsc_index);
176
177 mutex_lock(&rsc->client_lock);
178 list_add(&evt->list, &rsc->event_list);
179 mutex_unlock(&rsc->client_lock);
180
181 return evt;
182}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700183EXPORT_SYMBOL(sde_rsc_register_event);
Dhaval Patel031b4152017-03-16 13:03:18 -0700184
185void sde_rsc_unregister_event(struct sde_rsc_event *event)
186{
187 struct sde_rsc_priv *rsc;
188
189 if (!event) {
190 pr_debug("invalid event client\n");
191 goto end;
192 } else if (event->rsc_index >= MAX_RSC_COUNT) {
193 pr_err("invalid rsc index\n");
194 goto end;
195 }
196
197 pr_debug("event client destroyed\n");
198 rsc = rsc_prv_list[event->rsc_index];
199 if (!rsc)
200 goto end;
201
202 mutex_lock(&rsc->client_lock);
203 list_del_init(&event->list);
204 mutex_unlock(&rsc->client_lock);
205
206 kfree(event);
207end:
208 return;
209}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700210EXPORT_SYMBOL(sde_rsc_unregister_event);
Dhaval Patel031b4152017-03-16 13:03:18 -0700211
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700212static int sde_rsc_clk_enable(struct sde_power_handle *phandle,
213 struct sde_power_client *pclient, bool enable)
214{
215 int rc = 0;
216 struct dss_module_power *mp;
217
218 if (!phandle || !pclient) {
219 pr_err("invalid input argument\n");
220 return -EINVAL;
221 }
222
223 mp = &phandle->mp;
224
225 if (enable)
226 pclient->refcount++;
227 else if (pclient->refcount)
228 pclient->refcount--;
229
230 if (pclient->refcount)
231 pclient->usecase_ndx = VOTE_INDEX_LOW;
232 else
233 pclient->usecase_ndx = VOTE_INDEX_DISABLE;
234
235 if (phandle->current_usecase_ndx == pclient->usecase_ndx)
236 goto end;
237
238 if (enable) {
239 rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
240 if (rc) {
241 pr_err("clock enable failed rc:%d\n", rc);
242 goto end;
243 }
244 } else {
245 msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
246 }
247
248 phandle->current_usecase_ndx = pclient->usecase_ndx;
249
250end:
251 return rc;
252}
253
Dhaval Patel020f7e122016-11-15 14:39:18 -0800254static u32 sde_rsc_timer_calculate(struct sde_rsc_priv *rsc,
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800255 struct sde_rsc_cmd_config *cmd_config)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800256{
257 const u32 cxo_period_ns = 52;
258 u64 rsc_backoff_time_ns = RSC_BACKOFF_TIME_NS;
259 u64 rsc_mode_threshold_time_ns = RSC_MODE_THRESHOLD_TIME_IN_NS;
260 u64 rsc_time_slot_0_ns = RSC_TIME_SLOT_0_NS;
261 u64 rsc_time_slot_1_ns;
262 const u64 pdc_jitter = 20; /* 20% more */
263
264 u64 frame_time_ns, frame_jitter;
265 u64 line_time_ns, prefill_time_ns;
266 u64 pdc_backoff_time_ns;
267 s64 total;
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800268 int ret = 0;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800269
270 if (cmd_config)
271 memcpy(&rsc->cmd_config, cmd_config, sizeof(*cmd_config));
272
273 /* calculate for 640x480 60 fps resolution by default */
274 if (!rsc->cmd_config.fps)
275 rsc->cmd_config.fps = DEFAULT_PANEL_FPS;
276 if (!rsc->cmd_config.jitter)
277 rsc->cmd_config.jitter = DEFAULT_PANEL_JITTER;
278 if (!rsc->cmd_config.vtotal)
279 rsc->cmd_config.vtotal = DEFAULT_PANEL_VTOTAL;
280 if (!rsc->cmd_config.prefill_lines)
281 rsc->cmd_config.prefill_lines = DEFAULT_PANEL_PREFILL_LINES;
282 pr_debug("frame fps:%d jitter:%d vtotal:%d prefill lines:%d\n",
283 rsc->cmd_config.fps, rsc->cmd_config.jitter,
284 rsc->cmd_config.vtotal, rsc->cmd_config.prefill_lines);
285
286 /* 1 nano second */
287 frame_time_ns = TICKS_IN_NANO_SECOND;
288 frame_time_ns = div_u64(frame_time_ns, rsc->cmd_config.fps);
289
290 frame_jitter = frame_time_ns * rsc->cmd_config.jitter;
291 /* convert it to percentage */
292 frame_jitter = div_u64(frame_jitter, 100);
293
294 line_time_ns = frame_time_ns;
295 line_time_ns = div_u64(line_time_ns, rsc->cmd_config.vtotal);
296 prefill_time_ns = line_time_ns * rsc->cmd_config.prefill_lines;
297
298 total = frame_time_ns - frame_jitter - prefill_time_ns;
299 if (total < 0) {
300 pr_err("invalid total time period time:%llu jiter_time:%llu blanking time:%llu\n",
301 frame_time_ns, frame_jitter, prefill_time_ns);
302 total = 0;
303 }
304
305 total = div_u64(total, cxo_period_ns);
306 rsc->timer_config.static_wakeup_time_ns = total;
307
308 pr_debug("frame time:%llu frame jiter_time:%llu\n",
309 frame_time_ns, frame_jitter);
310 pr_debug("line time:%llu prefill time ps:%llu\n",
311 line_time_ns, prefill_time_ns);
312 pr_debug("static wakeup time:%lld cxo:%u\n", total, cxo_period_ns);
313
314 pdc_backoff_time_ns = rsc_backoff_time_ns;
315 rsc_backoff_time_ns = div_u64(rsc_backoff_time_ns, cxo_period_ns);
316 rsc->timer_config.rsc_backoff_time_ns = (u32) rsc_backoff_time_ns;
317
318 pdc_backoff_time_ns *= pdc_jitter;
319 pdc_backoff_time_ns = div_u64(pdc_backoff_time_ns, 100);
320 rsc->timer_config.pdc_backoff_time_ns = (u32) pdc_backoff_time_ns;
321
322 rsc_mode_threshold_time_ns =
323 div_u64(rsc_mode_threshold_time_ns, cxo_period_ns);
324 rsc->timer_config.rsc_mode_threshold_time_ns
325 = (u32) rsc_mode_threshold_time_ns;
326
327 /* time_slot_0 for mode0 latency */
328 rsc_time_slot_0_ns = div_u64(rsc_time_slot_0_ns, cxo_period_ns);
329 rsc->timer_config.rsc_time_slot_0_ns = (u32) rsc_time_slot_0_ns;
330
331 /* time_slot_1 for mode1 latency */
332 rsc_time_slot_1_ns = frame_time_ns;
333 rsc_time_slot_1_ns = div_u64(rsc_time_slot_1_ns, cxo_period_ns);
334 rsc->timer_config.rsc_time_slot_1_ns = (u32) rsc_time_slot_1_ns;
335
336 /* mode 2 is infinite */
337 rsc->timer_config.rsc_time_slot_2_ns = 0xFFFFFFFF;
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800338
339 if (rsc->hw_ops.init) {
340 ret = rsc->hw_ops.init(rsc);
341 if (ret)
342 pr_err("sde rsc: hw init failed ret:%d\n", ret);
343 }
344
345 return ret;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800346}
347
348static int sde_rsc_switch_to_idle(struct sde_rsc_priv *rsc)
349{
350 struct sde_rsc_client *client;
Dhaval Patela65b0f12017-03-16 00:36:55 -0700351 int rc = STATE_UPDATE_NOT_ALLOWED;
352 bool idle_switch = true;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800353
354 list_for_each_entry(client, &rsc->client_list, list)
Dhaval Patela65b0f12017-03-16 00:36:55 -0700355 if (client->current_state != SDE_RSC_IDLE_STATE) {
356 idle_switch = false;
357 break;
358 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800359
Dhaval Patela65b0f12017-03-16 00:36:55 -0700360 if (!idle_switch) {
361 /**
362 * following code needs to run the loop through each
363 * client because they might be in different order
364 * sorting is not possible; only preference is available
365 */
366
367 /* first check if any vid client active */
368 list_for_each_entry(client, &rsc->client_list, list)
369 if (client->current_state == SDE_RSC_VID_STATE)
370 return rc;
371
372 /* now try cmd state switch */
373 list_for_each_entry(client, &rsc->client_list, list)
374 if (client->current_state == SDE_RSC_CMD_STATE)
375 return TRY_CMD_MODE_SWITCH;
376
377 /* now try clk state switch */
378 list_for_each_entry(client, &rsc->client_list, list)
379 if (client->current_state == SDE_RSC_CLK_STATE)
380 return TRY_CLK_MODE_SWITCH;
381
382 } else if (rsc->hw_ops.state_update) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800383 rc = rsc->hw_ops.state_update(rsc, SDE_RSC_IDLE_STATE);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700384 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800385
386 return rc;
387}
388
Dhaval Patela65b0f12017-03-16 00:36:55 -0700389static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc,
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800390 struct sde_rsc_cmd_config *config,
Dhaval Patel020f7e122016-11-15 14:39:18 -0800391 struct sde_rsc_client *caller_client, bool wait_req)
392{
393 struct sde_rsc_client *client;
Dhaval Patela65b0f12017-03-16 00:36:55 -0700394 int rc = STATE_UPDATE_NOT_ALLOWED;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800395
396 if (!rsc->primary_client) {
397 pr_err("primary client not available for cmd state switch\n");
398 rc = -EINVAL;
399 goto end;
400 } else if (caller_client != rsc->primary_client) {
401 pr_err("primary client state:%d not cmd state request\n",
402 rsc->primary_client->current_state);
403 rc = -EINVAL;
404 goto end;
405 }
406
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800407 /* update timers - might not be available at next switch */
408 if (config)
409 sde_rsc_timer_calculate(rsc, config);
410
Dhaval Patel020f7e122016-11-15 14:39:18 -0800411 /* any one client in video state blocks the cmd state switch */
412 list_for_each_entry(client, &rsc->client_list, list)
413 if (client->current_state == SDE_RSC_VID_STATE)
414 goto end;
415
416 if (rsc->hw_ops.state_update)
417 rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CMD_STATE);
418
419 /* wait for vsync */
420 if (!rc && wait_req)
421 drm_wait_one_vblank(rsc->master_drm,
422 rsc->primary_client->crtc_id);
423end:
424 return rc;
425}
426
Dhaval Patela65b0f12017-03-16 00:36:55 -0700427static bool sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc)
428{
429 struct sde_rsc_client *client;
430 int rc = STATE_UPDATE_NOT_ALLOWED;
431
432 list_for_each_entry(client, &rsc->client_list, list)
433 if ((client->current_state == SDE_RSC_VID_STATE) ||
434 (client->current_state == SDE_RSC_CMD_STATE))
435 goto end;
436
Dhaval Patela65b0f12017-03-16 00:36:55 -0700437 if (rsc->hw_ops.state_update)
Dhaval Patelfbb11f02017-04-06 13:43:28 -0700438 rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CLK_STATE);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700439end:
440 return rc;
441}
442
Dhaval Patel020f7e122016-11-15 14:39:18 -0800443static bool sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc,
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800444 struct sde_rsc_cmd_config *config,
Dhaval Patel020f7e122016-11-15 14:39:18 -0800445 struct sde_rsc_client *caller_client, bool wait_req)
446{
447 int rc = 0;
448
449 /* update timers - might not be available at next switch */
450 if (config && (caller_client == rsc->primary_client))
451 sde_rsc_timer_calculate(rsc, config);
452
453 /* video state switch should be done immediately */
454 if (rsc->hw_ops.state_update)
455 rc = rsc->hw_ops.state_update(rsc, SDE_RSC_VID_STATE);
456
457 /* wait for vsync */
458 if (!rc && rsc->primary_client && wait_req)
459 drm_wait_one_vblank(rsc->master_drm,
460 rsc->primary_client->crtc_id);
461 return rc;
462}
463
464/**
465 * sde_rsc_client_state_update() - rsc client state update
Dhaval Patela65b0f12017-03-16 00:36:55 -0700466 * Video mode, cmd mode and clk state are suppoed as modes. A client need to
Dhaval Patel020f7e122016-11-15 14:39:18 -0800467 * set this property during panel config time. A switching client can set the
468 * property to change the state
469 *
470 * @client: Client pointer provided by sde_rsc_client_create().
471 * @state: Client state - video/cmd
472 * @config: fps, vtotal, porches, etc configuration for command mode
473 * panel
474 * @crtc_id: current client's crtc id
475 *
476 * Return: error code.
477 */
478int sde_rsc_client_state_update(struct sde_rsc_client *caller_client,
479 enum sde_rsc_state state,
Dhaval Patel82c8dbc2017-02-18 23:15:10 -0800480 struct sde_rsc_cmd_config *config, int crtc_id)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800481{
482 int rc = 0;
483 struct sde_rsc_priv *rsc;
484 bool wait_requested = false;
485
486 if (!caller_client) {
487 pr_err("invalid client for rsc state update\n");
488 return -EINVAL;
489 } else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
490 pr_err("invalid rsc index\n");
491 return -EINVAL;
492 }
493
494 rsc = rsc_prv_list[caller_client->rsc_index];
495 if (!rsc)
496 return -EINVAL;
497
498 mutex_lock(&rsc->client_lock);
499 caller_client->crtc_id = crtc_id;
500 caller_client->current_state = state;
501
502 if (rsc->master_drm == NULL) {
503 pr_err("invalid master component binding\n");
504 rc = -EINVAL;
505 goto end;
Dhaval Patela65b0f12017-03-16 00:36:55 -0700506 } else if ((rsc->current_state == state) && !config) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800507 pr_debug("no state change: %d\n", state);
508 goto end;
509 }
510
511 pr_debug("%pS: rsc state:%d request client:%s state:%d\n",
512 __builtin_return_address(0), rsc->current_state,
513 caller_client->name, state);
514
Dhaval Patela65b0f12017-03-16 00:36:55 -0700515 /* only switch state needs vsync wait */
516 wait_requested = (rsc->current_state == SDE_RSC_VID_STATE) ||
517 (rsc->current_state == SDE_RSC_CMD_STATE);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800518
519 if (rsc->power_collapse)
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700520 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800521
522 switch (state) {
523 case SDE_RSC_IDLE_STATE:
524 rc = sde_rsc_switch_to_idle(rsc);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700525
Dhaval Patel020f7e122016-11-15 14:39:18 -0800526 /* video state client might be exiting; try cmd state switch */
Dhaval Patela65b0f12017-03-16 00:36:55 -0700527 if (rc == TRY_CMD_MODE_SWITCH) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800528 rc = sde_rsc_switch_to_cmd(rsc, NULL,
529 rsc->primary_client, wait_requested);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700530 if (!rc)
531 state = SDE_RSC_CMD_STATE;
532
533 /* cmd state client might be exiting; try clk state switch */
534 } else if (rc == TRY_CLK_MODE_SWITCH) {
535 rc = sde_rsc_switch_to_clk(rsc);
536 if (!rc)
537 state = SDE_RSC_CLK_STATE;
538 }
Dhaval Patel020f7e122016-11-15 14:39:18 -0800539 break;
540
541 case SDE_RSC_CMD_STATE:
Dhaval Patel020f7e122016-11-15 14:39:18 -0800542 rc = sde_rsc_switch_to_cmd(rsc, config, caller_client,
543 wait_requested);
544 break;
545
546 case SDE_RSC_VID_STATE:
547 rc = sde_rsc_switch_to_vid(rsc, config, caller_client,
548 wait_requested);
549 break;
550
Dhaval Patela65b0f12017-03-16 00:36:55 -0700551 case SDE_RSC_CLK_STATE:
552 rc = sde_rsc_switch_to_clk(rsc);
553 break;
554
Dhaval Patel020f7e122016-11-15 14:39:18 -0800555 default:
556 pr_err("invalid state handling %d\n", state);
557 break;
558 }
559
Dhaval Patela65b0f12017-03-16 00:36:55 -0700560 if (rc == STATE_UPDATE_NOT_ALLOWED) {
561 rc = 0;
562 goto clk_disable;
563 } else if (rc) {
Dhaval Patel020f7e122016-11-15 14:39:18 -0800564 pr_err("state update failed rc:%d\n", rc);
Dhaval Patela65b0f12017-03-16 00:36:55 -0700565 goto clk_disable;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800566 }
567
568 pr_debug("state switch successfully complete: %d\n", state);
569 rsc->current_state = state;
570
Dhaval Patela65b0f12017-03-16 00:36:55 -0700571clk_disable:
Dhaval Patel020f7e122016-11-15 14:39:18 -0800572 if (rsc->power_collapse)
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700573 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800574end:
575 mutex_unlock(&rsc->client_lock);
576 return rc;
577}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700578EXPORT_SYMBOL(sde_rsc_client_state_update);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800579
580/**
581 * sde_rsc_client_vote() - ab/ib vote from rsc client
582 *
583 * @client: Client pointer provided by sde_rsc_client_create().
584 * @ab: aggregated bandwidth vote from client.
585 * @ib: instant bandwidth vote from client.
586 *
587 * Return: error code.
588 */
589int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
Dhaval Patel4d424602017-02-18 19:40:14 -0800590 u64 ab_vote, u64 ib_vote)
Dhaval Patel020f7e122016-11-15 14:39:18 -0800591{
592 int rc = 0;
593 struct sde_rsc_priv *rsc;
594 bool amc_mode = false;
595 enum rpmh_state state;
596
597 if (!caller_client) {
598 pr_err("invalid client for ab/ib vote\n");
599 return -EINVAL;
600 } else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
601 pr_err("invalid rsc index\n");
602 return -EINVAL;
603 }
604
605 rsc = rsc_prv_list[caller_client->rsc_index];
606 if (!rsc)
607 return -EINVAL;
608
609 if (caller_client != rsc->primary_client) {
610 pr_err("only primary client can use sde rsc:: curr client name:%s\n",
611 caller_client->name);
612 return -EINVAL;
613 }
614 pr_debug("client:%s ab:%llu ib:%llu\n",
615 caller_client->name, ab_vote, ib_vote);
616
617 mutex_lock(&rsc->client_lock);
618 if ((caller_client->current_state == SDE_RSC_IDLE_STATE) ||
619 (rsc->current_state == SDE_RSC_IDLE_STATE)) {
620
621 pr_err("invalid state: client state:%d rsc state:%d\n",
622 caller_client->current_state, rsc->current_state);
623 rc = -EINVAL;
624 goto end;
625 }
626
627 if (rsc->hw_ops.is_amc_mode)
628 amc_mode = rsc->hw_ops.is_amc_mode(rsc);
629
630 if (rsc->current_state == SDE_RSC_CMD_STATE)
Dhaval Patel4d424602017-02-18 19:40:14 -0800631 state = RPMH_WAKE_ONLY_STATE;
632 else if (amc_mode)
633 state = RPMH_ACTIVE_ONLY_STATE;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800634 else
Dhaval Patel4d424602017-02-18 19:40:14 -0800635 state = RPMH_AWAKE_STATE;
Dhaval Patel020f7e122016-11-15 14:39:18 -0800636
637 if (rsc->hw_ops.tcs_wait) {
638 rc = rsc->hw_ops.tcs_wait(rsc);
639 if (rc) {
640 pr_err("tcs is still busy; can't send command\n");
641 if (rsc->hw_ops.tcs_use_ok)
642 rsc->hw_ops.tcs_use_ok(rsc);
643 goto end;
644 }
645 }
646
647 sde_power_data_bus_set_quota(&rsc->phandle, rsc->pclient,
648 SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, ab_vote, ib_vote);
649
650 if (rsc->hw_ops.tcs_use_ok)
651 rsc->hw_ops.tcs_use_ok(rsc);
652
653end:
654 mutex_unlock(&rsc->client_lock);
655 return rc;
656}
Dhaval Patel49ef6d72017-03-26 09:35:53 -0700657EXPORT_SYMBOL(sde_rsc_client_vote);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800658
659static int _sde_debugfs_status_show(struct seq_file *s, void *data)
660{
661 struct sde_rsc_priv *rsc;
662 struct sde_rsc_client *client;
663 int ret;
664
665 if (!s || !s->private)
666 return -EINVAL;
667
668 rsc = s->private;
669
670 mutex_lock(&rsc->client_lock);
671 seq_printf(s, "rsc current state:%d\n", rsc->current_state);
672 seq_printf(s, "wraper backoff time(ns):%d\n",
673 rsc->timer_config.static_wakeup_time_ns);
674 seq_printf(s, "rsc backoff time(ns):%d\n",
675 rsc->timer_config.rsc_backoff_time_ns);
676 seq_printf(s, "pdc backoff time(ns):%d\n",
677 rsc->timer_config.pdc_backoff_time_ns);
678 seq_printf(s, "rsc mode threshold time(ns):%d\n",
679 rsc->timer_config.rsc_mode_threshold_time_ns);
680 seq_printf(s, "rsc time slot 0(ns):%d\n",
681 rsc->timer_config.rsc_time_slot_0_ns);
682 seq_printf(s, "rsc time slot 1(ns):%d\n",
683 rsc->timer_config.rsc_time_slot_1_ns);
684 seq_printf(s, "frame fps:%d jitter:%d vtotal:%d prefill lines:%d\n",
685 rsc->cmd_config.fps, rsc->cmd_config.jitter,
686 rsc->cmd_config.vtotal, rsc->cmd_config.prefill_lines);
687
688 seq_puts(s, "\n");
689
690 list_for_each_entry(client, &rsc->client_list, list)
691 seq_printf(s, "\t client:%s state:%d\n",
692 client->name, client->current_state);
693
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700694 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800695
696 if (rsc->hw_ops.debug_show) {
697 ret = rsc->hw_ops.debug_show(s, rsc);
698 if (ret)
699 pr_err("sde rsc: hw debug failed ret:%d\n", ret);
700 }
701
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700702 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800703 mutex_unlock(&rsc->client_lock);
704
705 return 0;
706}
707
708static int _sde_debugfs_status_open(struct inode *inode, struct file *file)
709{
710 return single_open(file, _sde_debugfs_status_show, inode->i_private);
711}
712
713static int _sde_debugfs_mode_ctrl_open(struct inode *inode, struct file *file)
714{
715 /* non-seekable */
716 file->private_data = inode->i_private;
717 return nonseekable_open(inode, file);
718}
719
720static ssize_t _sde_debugfs_mode_ctrl_read(struct file *file, char __user *buf,
721 size_t count, loff_t *ppos)
722{
723 struct sde_rsc_priv *rsc = file->private_data;
724 char buffer[MAX_BUFFER_SIZE];
725 int blen = 0;
726
727 if (*ppos || !rsc || !rsc->hw_ops.mode_ctrl)
728 return 0;
729
730 mutex_lock(&rsc->client_lock);
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700731 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800732
733 blen = rsc->hw_ops.mode_ctrl(rsc, MODE_READ, buffer,
734 MAX_BUFFER_SIZE, 0);
735
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700736 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800737 mutex_unlock(&rsc->client_lock);
738
739 if (blen < 0)
740 return 0;
741
742 if (copy_to_user(buf, buffer, blen))
743 return -EFAULT;
744
745 *ppos += blen;
746 return blen;
747}
748
749static ssize_t _sde_debugfs_mode_ctrl_write(struct file *file,
750 const char __user *p, size_t count, loff_t *ppos)
751{
752 struct sde_rsc_priv *rsc = file->private_data;
753 char *input, *mode;
754 u32 mode0_state = 0, mode1_state = 0, mode2_state = 0;
755
756 if (!rsc || !rsc->hw_ops.mode_ctrl)
757 return 0;
758
759 input = kmalloc(count, GFP_KERNEL);
760 if (!input)
761 return -ENOMEM;
762
763 if (copy_from_user(input, p, count)) {
764 kfree(input);
765 return -EFAULT;
766 }
767 input[count - 1] = '\0';
768
769 mutex_lock(&rsc->client_lock);
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700770 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800771
772 mode = strnstr(input, "mode0=", strlen("mode0="));
773 if (mode) {
774 mode0_state = mode[0] - '0';
775 mode0_state &= BIT(0);
776 rsc->hw_ops.mode_ctrl(rsc, MODE0_UPDATE, NULL, 0, mode0_state);
777 goto end;
778 }
779
780 mode = strnstr(input, "mode1=", strlen("mode1="));
781 if (mode) {
782 mode1_state = mode[0] - '0';
783 mode1_state &= BIT(0);
784 rsc->hw_ops.mode_ctrl(rsc, MODE1_UPDATE, NULL, 0, mode1_state);
785 goto end;
786 }
787
788 mode = strnstr(input, "mode2=", strlen("mode2="));
789 if (mode) {
790 mode2_state = mode[0] - '0';
791 mode2_state &= BIT(0);
792 rsc->hw_ops.mode_ctrl(rsc, MODE2_UPDATE, NULL, 0, mode2_state);
793 }
794
795end:
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700796 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800797 mutex_unlock(&rsc->client_lock);
798
799 pr_err("req: mode0:%d mode1:%d mode2:%d\n", mode0_state, mode1_state,
800 mode2_state);
801 kfree(input);
802 return count;
803}
804
805static int _sde_debugfs_vsync_mode_open(struct inode *inode, struct file *file)
806{
807 /* non-seekable */
808 file->private_data = inode->i_private;
809 return nonseekable_open(inode, file);
810}
811
812static ssize_t _sde_debugfs_vsync_mode_read(struct file *file, char __user *buf,
813 size_t count, loff_t *ppos)
814{
815 struct sde_rsc_priv *rsc = file->private_data;
816 char buffer[MAX_BUFFER_SIZE];
817 int blen = 0;
818
819 if (*ppos || !rsc || !rsc->hw_ops.hw_vsync)
820 return 0;
821
822 mutex_lock(&rsc->client_lock);
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700823 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800824
825 blen = rsc->hw_ops.hw_vsync(rsc, VSYNC_READ, buffer,
826 MAX_BUFFER_SIZE, 0);
827
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700828 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800829 mutex_unlock(&rsc->client_lock);
830
831 if (blen < 0)
832 return 0;
833
834 if (copy_to_user(buf, buffer, blen))
835 return -EFAULT;
836
837 *ppos += blen;
838 return blen;
839}
840
841static ssize_t _sde_debugfs_vsync_mode_write(struct file *file,
842 const char __user *p, size_t count, loff_t *ppos)
843{
844 struct sde_rsc_priv *rsc = file->private_data;
845 char *input, *vsync_mode;
846 u32 vsync_state = 0;
847
848 if (!rsc || !rsc->hw_ops.hw_vsync)
849 return 0;
850
851 input = kmalloc(count, GFP_KERNEL);
852 if (!input)
853 return -ENOMEM;
854
855 if (copy_from_user(input, p, count)) {
856 kfree(input);
857 return -EFAULT;
858 }
859 input[count - 1] = '\0';
860
861 vsync_mode = strnstr(input, "vsync_mode=", strlen("vsync_mode="));
862 if (vsync_mode) {
863 vsync_state = vsync_mode[0] - '0';
864 vsync_state &= 0x7;
865 }
866
867 mutex_lock(&rsc->client_lock);
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700868 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800869
870 if (vsync_state)
871 rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL,
872 0, vsync_state - 1);
873 else
874 rsc->hw_ops.hw_vsync(rsc, VSYNC_DISABLE, NULL, 0, 0);
875
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700876 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800877 mutex_unlock(&rsc->client_lock);
878
879 kfree(input);
880 return count;
881}
882
883static const struct file_operations debugfs_status_fops = {
884 .open = _sde_debugfs_status_open,
885 .read = seq_read,
886 .llseek = seq_lseek,
887 .release = single_release,
888};
889
890static const struct file_operations mode_control_fops = {
891 .open = _sde_debugfs_mode_ctrl_open,
892 .read = _sde_debugfs_mode_ctrl_read,
893 .write = _sde_debugfs_mode_ctrl_write,
894};
895
896static const struct file_operations vsync_status_fops = {
897 .open = _sde_debugfs_vsync_mode_open,
898 .read = _sde_debugfs_vsync_mode_read,
899 .write = _sde_debugfs_vsync_mode_write,
900};
901
902static void _sde_rsc_init_debugfs(struct sde_rsc_priv *rsc, char *name)
903{
904 rsc->debugfs_root = debugfs_create_dir(name, NULL);
905 if (!rsc->debugfs_root)
906 return;
907
908 /* don't error check these */
909 debugfs_create_file("status", 0444, rsc->debugfs_root, rsc,
910 &debugfs_status_fops);
911 debugfs_create_file("mode_control", 0644, rsc->debugfs_root, rsc,
912 &mode_control_fops);
913 debugfs_create_file("vsync_mode", 0644, rsc->debugfs_root, rsc,
914 &vsync_status_fops);
915 debugfs_create_x32("debug_mode", 0644, rsc->debugfs_root,
916 &rsc->debug_mode);
917}
918
919static void sde_rsc_deinit(struct platform_device *pdev,
920 struct sde_rsc_priv *rsc)
921{
922 if (!rsc)
923 return;
924
925 if (rsc->pclient)
Dhaval Patelfcd9e912017-03-16 00:54:09 -0700926 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
Dhaval Patel020f7e122016-11-15 14:39:18 -0800927 if (rsc->fs)
928 devm_regulator_put(rsc->fs);
929 if (rsc->wrapper_io.base)
930 msm_dss_iounmap(&rsc->wrapper_io);
931 if (rsc->drv_io.base)
932 msm_dss_iounmap(&rsc->drv_io);
933 if (rsc->pclient)
934 sde_power_client_destroy(&rsc->phandle, rsc->pclient);
935
936 sde_power_resource_deinit(pdev, &rsc->phandle);
937 debugfs_remove_recursive(rsc->debugfs_root);
938 kfree(rsc);
939}
940
941/**
942 * sde_rsc_bind - bind rsc device with controlling device
943 * @dev: Pointer to base of platform device
944 * @master: Pointer to container of drm device
945 * @data: Pointer to private data
946 * Returns: Zero on success
947 */
948static int sde_rsc_bind(struct device *dev,
949 struct device *master,
950 void *data)
951{
952 struct sde_rsc_priv *rsc;
953 struct drm_device *drm;
954 struct platform_device *pdev = to_platform_device(dev);
955
956 if (!dev || !pdev || !master) {
957 pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n",
958 dev, pdev, master);
959 return -EINVAL;
960 }
961
962 drm = dev_get_drvdata(master);
963 rsc = platform_get_drvdata(pdev);
964 if (!drm || !rsc) {
965 pr_err("invalid param(s), drm %pK, rsc %pK\n",
966 drm, rsc);
967 return -EINVAL;
968 }
969
970 mutex_lock(&rsc->client_lock);
971 rsc->master_drm = drm;
972 mutex_unlock(&rsc->client_lock);
973
974 return 0;
975}
976
977/**
978 * sde_rsc_unbind - unbind rsc from controlling device
979 * @dev: Pointer to base of platform device
980 * @master: Pointer to container of drm device
981 * @data: Pointer to private data
982 */
983static void sde_rsc_unbind(struct device *dev,
984 struct device *master, void *data)
985{
986 struct sde_rsc_priv *rsc;
987 struct platform_device *pdev = to_platform_device(dev);
988
989 if (!dev || !pdev) {
990 pr_err("invalid param(s)\n");
991 return;
992 }
993
994 rsc = platform_get_drvdata(pdev);
995 if (!rsc) {
996 pr_err("invalid display rsc\n");
997 return;
998 }
999
1000 mutex_lock(&rsc->client_lock);
1001 rsc->master_drm = NULL;
1002 mutex_unlock(&rsc->client_lock);
1003}
1004
1005static const struct component_ops sde_rsc_comp_ops = {
1006 .bind = sde_rsc_bind,
1007 .unbind = sde_rsc_unbind,
1008};
1009
1010static int sde_rsc_probe(struct platform_device *pdev)
1011{
1012 int ret;
1013 struct sde_rsc_priv *rsc;
1014 static int counter;
1015 char name[MAX_RSC_CLIENT_NAME_LEN];
1016
1017 rsc = kzalloc(sizeof(*rsc), GFP_KERNEL);
1018 if (!rsc) {
1019 ret = -ENOMEM;
1020 goto rsc_alloc_fail;
1021 }
1022
1023 platform_set_drvdata(pdev, rsc);
1024 of_property_read_u32(pdev->dev.of_node, "qcom,sde-rsc-version",
1025 &rsc->version);
1026
1027 ret = sde_power_resource_init(pdev, &rsc->phandle);
1028 if (ret) {
1029 pr_err("sde rsc:power resource init failed ret:%d\n", ret);
1030 goto sde_rsc_fail;
1031 }
1032
1033 rsc->pclient = sde_power_client_create(&rsc->phandle, "rsc");
1034 if (IS_ERR_OR_NULL(rsc->pclient)) {
1035 ret = PTR_ERR(rsc->pclient);
1036 rsc->pclient = NULL;
1037 pr_err("sde rsc:power client create failed ret:%d\n", ret);
1038 goto sde_rsc_fail;
1039 }
1040
1041 ret = msm_dss_ioremap_byname(pdev, &rsc->wrapper_io, "wrapper");
1042 if (ret) {
1043 pr_err("sde rsc: wrapper io data mapping failed ret=%d\n", ret);
1044 goto sde_rsc_fail;
1045 }
1046
1047 ret = msm_dss_ioremap_byname(pdev, &rsc->drv_io, "drv");
1048 if (ret) {
1049 pr_err("sde rsc: drv io data mapping failed ret:%d\n", ret);
1050 goto sde_rsc_fail;
1051 }
1052
1053 rsc->fs = devm_regulator_get(&pdev->dev, "vdd");
1054 if (IS_ERR_OR_NULL(rsc->fs)) {
1055 rsc->fs = NULL;
1056 pr_err("unable to get regulator\n");
1057 goto sde_rsc_fail;
1058 }
1059
1060 ret = sde_rsc_hw_register(rsc);
1061 if (ret) {
1062 pr_err("sde rsc: hw register failed ret:%d\n", ret);
1063 goto sde_rsc_fail;
1064 }
1065
Dhaval Patelfcd9e912017-03-16 00:54:09 -07001066 if (sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true)) {
Dhaval Patel020f7e122016-11-15 14:39:18 -08001067 pr_err("failed to enable sde rsc power resources\n");
1068 goto sde_rsc_fail;
1069 }
1070
Dhaval Patel82c8dbc2017-02-18 23:15:10 -08001071 if (sde_rsc_timer_calculate(rsc, NULL))
1072 goto sde_rsc_fail;
Dhaval Patel020f7e122016-11-15 14:39:18 -08001073
Dhaval Patelfcd9e912017-03-16 00:54:09 -07001074 sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
1075
Dhaval Patel020f7e122016-11-15 14:39:18 -08001076 INIT_LIST_HEAD(&rsc->client_list);
Dhaval Patelfbb11f02017-04-06 13:43:28 -07001077 INIT_LIST_HEAD(&rsc->event_list);
Dhaval Patel020f7e122016-11-15 14:39:18 -08001078 mutex_init(&rsc->client_lock);
1079
1080 pr_info("sde rsc index:%d probed successfully\n",
1081 SDE_RSC_INDEX + counter);
1082
1083 rsc_prv_list[SDE_RSC_INDEX + counter] = rsc;
1084 snprintf(name, MAX_RSC_CLIENT_NAME_LEN, "%s%d", "sde_rsc", counter);
1085 _sde_rsc_init_debugfs(rsc, name);
1086 counter++;
Dhaval Patelfbb11f02017-04-06 13:43:28 -07001087 rsc->power_collapse = true;
Dhaval Patel020f7e122016-11-15 14:39:18 -08001088
1089 ret = component_add(&pdev->dev, &sde_rsc_comp_ops);
1090 if (ret)
1091 pr_debug("component add failed, ret=%d\n", ret);
1092 ret = 0;
1093
1094 return ret;
1095
1096sde_rsc_fail:
1097 sde_rsc_deinit(pdev, rsc);
1098rsc_alloc_fail:
1099 return ret;
1100}
1101
1102static int sde_rsc_remove(struct platform_device *pdev)
1103{
1104 struct sde_rsc_priv *rsc = platform_get_drvdata(pdev);
1105
1106 sde_rsc_deinit(pdev, rsc);
1107 return 0;
1108}
1109
1110static const struct of_device_id dt_match[] = {
1111 { .compatible = "qcom,sde-rsc"},
1112 {}
1113};
1114
1115MODULE_DEVICE_TABLE(of, dt_match);
1116
1117static struct platform_driver sde_rsc_platform_driver = {
1118 .probe = sde_rsc_probe,
1119 .remove = sde_rsc_remove,
1120 .driver = {
1121 .name = "sde_rsc",
1122 .of_match_table = dt_match,
1123 },
1124};
1125
1126static int __init sde_rsc_register(void)
1127{
1128 return platform_driver_register(&sde_rsc_platform_driver);
1129}
1130
1131static void __exit sde_rsc_unregister(void)
1132{
1133 platform_driver_unregister(&sde_rsc_platform_driver);
1134}
1135
1136module_init(sde_rsc_register);
1137module_exit(sde_rsc_unregister);