Skip to content

Commit 8238395

Browse files
committed
firmware: arm_scmi: Make use SCMI v2.0 fastchannel for performance protocol
SCMI v2.0 adds support for "FastChannel" which do not use a message header as they are specialized for a single message. Only PERFORMANCE_LIMITS_{SET,GET} and PERFORMANCE_LEVEL_{SET,GET} commands are supported over fastchannels. As they are optional, they need to be discovered by PERFORMANCE_DESCRIBE_FASTCHANNEL command. Further {LIMIT,LEVEL}_SET commands can have optional doorbell support. Add support for making use of these fastchannels. Cc: Ionela Voinescu <[email protected]> Cc: Chris Redpath <[email protected]> Cc: Quentin Perret <[email protected]> Reviewed-by: Peng Fan <[email protected]> Signed-off-by: Sudeep Holla <[email protected]>
1 parent ac8aaf3 commit 8238395

File tree

1 file changed

+99
-4
lines changed
  • drivers/firmware/arm_scmi

1 file changed

+99
-4
lines changed

drivers/firmware/arm_scmi/perf.c

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/bits.h>
99
#include <linux/of.h>
1010
#include <linux/io.h>
11+
#include <linux/io-64-nonatomic-hi-lo.h>
1112
#include <linux/platform_device.h>
1213
#include <linux/pm_opp.h>
1314
#include <linux/sort.h>
@@ -293,7 +294,41 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain,
293294
return ret;
294295
}
295296

296-
static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain,
297+
#define SCMI_PERF_FC_RING_DB(w) \
298+
do { \
299+
u##w val = 0; \
300+
\
301+
if (db->mask) \
302+
val = ioread##w(db->addr) & db->mask; \
303+
iowrite##w((u##w)db->set | val, db->addr); \
304+
} while (0)
305+
306+
static void scmi_perf_fc_ring_db(struct scmi_fc_db_info *db)
307+
{
308+
if (!db || !db->addr)
309+
return;
310+
311+
if (db->width == 1)
312+
SCMI_PERF_FC_RING_DB(8);
313+
else if (db->width == 2)
314+
SCMI_PERF_FC_RING_DB(16);
315+
else if (db->width == 4)
316+
SCMI_PERF_FC_RING_DB(32);
317+
else /* db->width == 8 */
318+
#ifdef CONFIG_64BIT
319+
SCMI_PERF_FC_RING_DB(64);
320+
#else
321+
{
322+
u64 val = 0;
323+
324+
if (db->mask)
325+
val = ioread64_hi_lo(db->addr) & db->mask;
326+
iowrite64_hi_lo(db->set, db->addr);
327+
}
328+
#endif
329+
}
330+
331+
static int scmi_perf_mb_limits_set(const struct scmi_handle *handle, u32 domain,
297332
u32 max_perf, u32 min_perf)
298333
{
299334
int ret;
@@ -316,7 +351,23 @@ static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain,
316351
return ret;
317352
}
318353

319-
static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain,
354+
static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain,
355+
u32 max_perf, u32 min_perf)
356+
{
357+
struct scmi_perf_info *pi = handle->perf_priv;
358+
struct perf_dom_info *dom = pi->dom_info + domain;
359+
360+
if (dom->fc_info && dom->fc_info->limit_set_addr) {
361+
iowrite32(max_perf, dom->fc_info->limit_set_addr);
362+
iowrite32(min_perf, dom->fc_info->limit_set_addr + 4);
363+
scmi_perf_fc_ring_db(dom->fc_info->limit_set_db);
364+
return 0;
365+
}
366+
367+
return scmi_perf_mb_limits_set(handle, domain, max_perf, min_perf);
368+
}
369+
370+
static int scmi_perf_mb_limits_get(const struct scmi_handle *handle, u32 domain,
320371
u32 *max_perf, u32 *min_perf)
321372
{
322373
int ret;
@@ -342,7 +393,22 @@ static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain,
342393
return ret;
343394
}
344395

345-
static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain,
396+
static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain,
397+
u32 *max_perf, u32 *min_perf)
398+
{
399+
struct scmi_perf_info *pi = handle->perf_priv;
400+
struct perf_dom_info *dom = pi->dom_info + domain;
401+
402+
if (dom->fc_info && dom->fc_info->limit_get_addr) {
403+
*max_perf = ioread32(dom->fc_info->limit_get_addr);
404+
*min_perf = ioread32(dom->fc_info->limit_get_addr + 4);
405+
return 0;
406+
}
407+
408+
return scmi_perf_mb_limits_get(handle, domain, max_perf, min_perf);
409+
}
410+
411+
static int scmi_perf_mb_level_set(const struct scmi_handle *handle, u32 domain,
346412
u32 level, bool poll)
347413
{
348414
int ret;
@@ -365,7 +431,22 @@ static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain,
365431
return ret;
366432
}
367433

368-
static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain,
434+
static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain,
435+
u32 level, bool poll)
436+
{
437+
struct scmi_perf_info *pi = handle->perf_priv;
438+
struct perf_dom_info *dom = pi->dom_info + domain;
439+
440+
if (dom->fc_info && dom->fc_info->level_set_addr) {
441+
iowrite32(level, dom->fc_info->level_set_addr);
442+
scmi_perf_fc_ring_db(dom->fc_info->level_set_db);
443+
return 0;
444+
}
445+
446+
return scmi_perf_mb_level_set(handle, domain, level, poll);
447+
}
448+
449+
static int scmi_perf_mb_level_get(const struct scmi_handle *handle, u32 domain,
369450
u32 *level, bool poll)
370451
{
371452
int ret;
@@ -387,6 +468,20 @@ static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain,
387468
return ret;
388469
}
389470

471+
static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain,
472+
u32 *level, bool poll)
473+
{
474+
struct scmi_perf_info *pi = handle->perf_priv;
475+
struct perf_dom_info *dom = pi->dom_info + domain;
476+
477+
if (dom->fc_info && dom->fc_info->level_get_addr) {
478+
*level = ioread32(dom->fc_info->level_get_addr);
479+
return 0;
480+
}
481+
482+
return scmi_perf_mb_level_get(handle, domain, level, poll);
483+
}
484+
390485
static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size)
391486
{
392487
if ((msg == PERF_LEVEL_GET || msg == PERF_LEVEL_SET) && size == 4)

0 commit comments

Comments
 (0)