Skip to content

Commit 9600b8b

Browse files
gwendalcrTzung-Bi Shih
authored andcommitted
platform/chrome: lightbar: Add support for large sequence
Current sequences are limited to 192 bytes. Increase support to whatever the EC support. If the sequence is too long, the EC will return an OVERFLOW error. Test: Check sending a large sequence is received by the EC. Signed-off-by: Gwendal Grignou <gwendal@google.com> Link: https://lore.kernel.org/r/20260130081351.487517-2-gwendal@google.com Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
1 parent 2d8251d commit 9600b8b

2 files changed

Lines changed: 74 additions & 27 deletions

File tree

drivers/platform/chrome/cros_ec_lightbar.c

Lines changed: 61 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ static bool userspace_control;
3737
*/
3838
static bool has_manual_suspend;
3939

40+
/*
41+
* Lightbar version
42+
*/
43+
static int lb_version;
44+
4045
static ssize_t interval_msec_show(struct device *dev,
4146
struct device_attribute *attr, char *buf)
4247
{
@@ -93,18 +98,20 @@ static int lb_throttle(void)
9398

9499
static struct cros_ec_command *alloc_lightbar_cmd_msg(struct cros_ec_dev *ec)
95100
{
101+
int len = max(ec->ec_dev->max_response, ec->ec_dev->max_request);
96102
struct cros_ec_command *msg;
97-
int len;
98-
99-
len = max(sizeof(struct ec_params_lightbar),
100-
sizeof(struct ec_response_lightbar));
101103

102104
msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL);
103105
if (!msg)
104106
return NULL;
105107

106108
msg->version = 0;
107109
msg->command = EC_CMD_LIGHTBAR_CMD + ec->cmd_offset;
110+
/*
111+
* Default sizes for regular commands.
112+
* Can be set smaller to optimize transfer,
113+
* larger when sending large light sequences.
114+
*/
108115
msg->outsize = sizeof(struct ec_params_lightbar);
109116
msg->insize = sizeof(struct ec_response_lightbar);
110117

@@ -471,25 +478,34 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
471478
static ssize_t program_store(struct device *dev, struct device_attribute *attr,
472479
const char *buf, size_t count)
473480
{
474-
int extra_bytes, max_size, ret;
481+
size_t extra_bytes, max_size;
475482
struct ec_params_lightbar *param;
476483
struct cros_ec_command *msg;
477484
struct cros_ec_dev *ec = to_cros_ec_dev(dev);
485+
int ret;
478486

479487
/*
480488
* We might need to reject the program for size reasons. The EC
481489
* enforces a maximum program size, but we also don't want to try
482490
* and send a program that is too big for the protocol. In order
483491
* to ensure the latter, we also need to ensure we have extra bytes
484492
* to represent the rest of the packet.
493+
* With V3, larger program can be sent, limited only by the EC.
494+
* Only the protocol limit the payload size.
485495
*/
486-
extra_bytes = sizeof(*param) - sizeof(param->set_program.data);
487-
max_size = min(EC_LB_PROG_LEN, ec->ec_dev->max_request - extra_bytes);
488-
if (count > max_size) {
489-
dev_err(dev, "Program is %u bytes, too long to send (max: %u)",
490-
(unsigned int)count, max_size);
491-
492-
return -EINVAL;
496+
if (lb_version < 3) {
497+
extra_bytes = sizeof(*param) - sizeof(param->set_program.data);
498+
max_size = min(EC_LB_PROG_LEN, ec->ec_dev->max_request - extra_bytes);
499+
if (count > max_size) {
500+
dev_err(dev, "Program is %zu bytes, too long to send (max: %zu)",
501+
count, max_size);
502+
503+
return -EINVAL;
504+
}
505+
} else {
506+
extra_bytes = offsetof(typeof(*param), set_program_ex) +
507+
sizeof(param->set_program_ex);
508+
max_size = ec->ec_dev->max_request - extra_bytes;
493509
}
494510

495511
msg = alloc_lightbar_cmd_msg(ec);
@@ -499,26 +515,44 @@ static ssize_t program_store(struct device *dev, struct device_attribute *attr,
499515
ret = lb_throttle();
500516
if (ret)
501517
goto exit;
518+
param = (struct ec_params_lightbar *)msg->data;
502519

503-
dev_info(dev, "Copying %zu byte program to EC", count);
520+
if (lb_version < 3) {
521+
dev_info(dev, "Copying %zu byte program to EC", count);
504522

505-
param = (struct ec_params_lightbar *)msg->data;
506-
param->cmd = LIGHTBAR_CMD_SET_PROGRAM;
523+
param->cmd = LIGHTBAR_CMD_SET_PROGRAM;
507524

508-
param->set_program.size = count;
509-
memcpy(param->set_program.data, buf, count);
525+
param->set_program.size = count;
526+
memcpy(param->set_program.data, buf, count);
510527

511-
/*
512-
* We need to set the message size manually or else it will use
513-
* EC_LB_PROG_LEN. This might be too long, and the program
514-
* is unlikely to use all of the space.
515-
*/
516-
msg->outsize = count + extra_bytes;
528+
/*
529+
* We need to set the message size manually or else it will use
530+
* EC_LB_PROG_LEN. This might be too long, and the program
531+
* is unlikely to use all of the space.
532+
*/
533+
msg->outsize = count + extra_bytes;
517534

518-
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
519-
if (ret < 0)
520-
goto exit;
535+
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
536+
if (ret < 0)
537+
goto exit;
538+
} else {
539+
size_t offset = 0;
540+
size_t payload = 0;
541+
542+
param->cmd = LIGHTBAR_CMD_SET_PROGRAM_EX;
543+
while (offset < count) {
544+
payload = min(max_size, count - offset);
545+
param->set_program_ex.offset = offset;
546+
param->set_program_ex.size = payload;
547+
memcpy(param->set_program_ex.data, &buf[offset], payload);
548+
msg->outsize = payload + extra_bytes;
521549

550+
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
551+
if (ret < 0)
552+
goto exit;
553+
offset += payload;
554+
}
555+
}
522556
ret = count;
523557
exit:
524558
kfree(msg);
@@ -596,7 +630,7 @@ static int cros_ec_lightbar_probe(struct platform_device *pd)
596630
* Ask then for the lightbar version, if it's 0 then the 'cros_ec'
597631
* doesn't have a lightbar.
598632
*/
599-
if (!get_lightbar_version(ec_dev, NULL, NULL))
633+
if (!get_lightbar_version(ec_dev, &lb_version, NULL))
600634
return -ENODEV;
601635

602636
/* Take control of the lightbar from the EC. */

include/linux/platform_data/cros_ec_commands.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,6 +2020,17 @@ struct lightbar_program {
20202020
uint8_t data[EC_LB_PROG_LEN];
20212021
} __ec_todo_unpacked;
20222022

2023+
/*
2024+
* Lightbar program for large sequences. Sequences are sent in pieces, with
2025+
* increasing offset. The sequences are still limited by the amount reserved in
2026+
* EC RAM.
2027+
*/
2028+
struct lightbar_program_ex {
2029+
uint16_t offset;
2030+
uint8_t size;
2031+
uint8_t data[0];
2032+
} __ec_todo_unpacked;
2033+
20232034
struct ec_params_lightbar {
20242035
uint8_t cmd; /* Command (see enum lightbar_command) */
20252036
union {
@@ -2066,6 +2077,7 @@ struct ec_params_lightbar {
20662077
struct lightbar_params_v2_colors set_v2par_colors;
20672078

20682079
struct lightbar_program set_program;
2080+
struct lightbar_program_ex set_program_ex;
20692081
};
20702082
} __ec_todo_packed;
20712083

@@ -2154,6 +2166,7 @@ enum lightbar_command {
21542166
LIGHTBAR_CMD_GET_PARAMS_V2_COLORS = 32,
21552167
LIGHTBAR_CMD_SET_PARAMS_V2_COLORS = 33,
21562168
LIGHTBAR_CMD_GET_PARAMS_V3 = 34,
2169+
LIGHTBAR_CMD_SET_PROGRAM_EX = 35,
21572170
LIGHTBAR_NUM_CMDS
21582171
};
21592172

0 commit comments

Comments
 (0)