Merge tag 'arm-dt-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / drivers / firmware / arm_scmi / clock.c
index c7a83f6..3ed7ae0 100644 (file)
@@ -194,6 +194,7 @@ static int rate_cmp_func(const void *_r1, const void *_r2)
 }
 
 struct scmi_clk_ipriv {
+       struct device *dev;
        u32 clk_id;
        struct scmi_clock_info *clk;
 };
@@ -223,6 +224,29 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
        st->num_returned = NUM_RETURNED(flags);
        p->clk->rate_discrete = RATE_DISCRETE(flags);
 
+       /* Warn about out of spec replies ... */
+       if (!p->clk->rate_discrete &&
+           (st->num_returned != 3 || st->num_remaining != 0)) {
+               dev_warn(p->dev,
+                        "Out-of-spec CLOCK_DESCRIBE_RATES reply for %s - returned:%d remaining:%d rx_len:%zd\n",
+                        p->clk->name, st->num_returned, st->num_remaining,
+                        st->rx_len);
+
+               /*
+                * A known quirk: a triplet is returned but num_returned != 3
+                * Check for a safe payload size and fix.
+                */
+               if (st->num_returned != 3 && st->num_remaining == 0 &&
+                   st->rx_len == sizeof(*r) + sizeof(__le32) * 2 * 3) {
+                       st->num_returned = 3;
+                       st->num_remaining = 0;
+               } else {
+                       dev_err(p->dev,
+                               "Cannot fix out-of-spec reply !\n");
+                       return -EPROTO;
+               }
+       }
+
        return 0;
 }
 
@@ -255,7 +279,6 @@ iter_clk_describe_process_response(const struct scmi_protocol_handle *ph,
 
                *rate = RATE_TO_U64(r->rate[st->loop_idx]);
                p->clk->list.num_rates++;
-               //XXX dev_dbg(ph->dev, "Rate %llu Hz\n", *rate);
        }
 
        return ret;
@@ -275,6 +298,7 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
        struct scmi_clk_ipriv cpriv = {
                .clk_id = clk_id,
                .clk = clk,
+               .dev = ph->dev,
        };
 
        iter = ph->hops->iter_response_init(ph, &ops, SCMI_MAX_NUM_RATES,