Lines Matching +full:ast2600 +full:- +full:peci
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2012-2017 ASPEED Technology Inc.
3 // Copyright (c) 2018-2021 Intel Corporation
10 #include <linux/clk-provider.h>
19 #include <linux/peci.h>
23 /* ASPEED PECI Registers */
144 u32 val = readl(priv->base + ASPEED_PECI_CTRL); in aspeed_peci_controller_enable()
149 writel(val, priv->base + ASPEED_PECI_CTRL); in aspeed_peci_controller_enable()
157 writel(ASPEED_PECI_INT_MASK, priv->base + ASPEED_PECI_INT_STS); in aspeed_peci_init_regs()
162 writel(val, priv->base + ASPEED_PECI_INT_CTRL); in aspeed_peci_init_regs()
165 writel(val, priv->base + ASPEED_PECI_CTRL); in aspeed_peci_init_regs()
170 u32 cmd_sts = readl(priv->base + ASPEED_PECI_CMD); in aspeed_peci_check_idle()
176 * where the hardware is not in idle state - we need to reset and in aspeed_peci_check_idle()
180 ret = reset_control_assert(priv->rst); in aspeed_peci_check_idle()
182 dev_err(priv->dev, "cannot assert reset control\n"); in aspeed_peci_check_idle()
186 ret = reset_control_deassert(priv->rst); in aspeed_peci_check_idle()
188 dev_err(priv->dev, "cannot deassert reset control\n"); in aspeed_peci_check_idle()
194 ret = clk_set_rate(priv->clk, priv->clk_frequency); in aspeed_peci_check_idle()
196 dev_err(priv->dev, "cannot set clock frequency\n"); in aspeed_peci_check_idle()
203 return readl_poll_timeout(priv->base + ASPEED_PECI_CMD, in aspeed_peci_check_idle()
213 struct aspeed_peci *priv = dev_get_drvdata(controller->dev.parent); in aspeed_peci_xfer()
214 unsigned long timeout = msecs_to_jiffies(priv->cmd_timeout_ms); in aspeed_peci_xfer()
218 if (req->tx.len > ASPEED_PECI_DATA_BUF_SIZE_MAX || in aspeed_peci_xfer()
219 req->rx.len > ASPEED_PECI_DATA_BUF_SIZE_MAX) in aspeed_peci_xfer()
220 return -EINVAL; in aspeed_peci_xfer()
225 return ret; /* -ETIMEDOUT */ in aspeed_peci_xfer()
227 spin_lock_irq(&priv->lock); in aspeed_peci_xfer()
228 reinit_completion(&priv->xfer_complete); in aspeed_peci_xfer()
231 FIELD_PREP(ASPEED_PECI_WR_LEN_MASK, req->tx.len) | in aspeed_peci_xfer()
232 FIELD_PREP(ASPEED_PECI_RD_LEN_MASK, req->rx.len); in aspeed_peci_xfer()
234 writel(peci_head, priv->base + ASPEED_PECI_RW_LENGTH); in aspeed_peci_xfer()
236 for (i = 0; i < req->tx.len; i += 4) { in aspeed_peci_xfer()
239 writel(get_unaligned_le32(&req->tx.buf[i]), priv->base + reg); in aspeed_peci_xfer()
243 dev_dbg(priv->dev, "HEAD : %#08x\n", peci_head); in aspeed_peci_xfer()
244 print_hex_dump_bytes("TX : ", DUMP_PREFIX_NONE, req->tx.buf, req->tx.len); in aspeed_peci_xfer()
247 priv->status = 0; in aspeed_peci_xfer()
248 writel(ASPEED_PECI_CMD_FIRE, priv->base + ASPEED_PECI_CMD); in aspeed_peci_xfer()
249 spin_unlock_irq(&priv->lock); in aspeed_peci_xfer()
251 ret = wait_for_completion_interruptible_timeout(&priv->xfer_complete, timeout); in aspeed_peci_xfer()
256 dev_dbg(priv->dev, "timeout waiting for a response\n"); in aspeed_peci_xfer()
257 return -ETIMEDOUT; in aspeed_peci_xfer()
260 spin_lock_irq(&priv->lock); in aspeed_peci_xfer()
262 if (priv->status != ASPEED_PECI_INT_CMD_DONE) { in aspeed_peci_xfer()
263 spin_unlock_irq(&priv->lock); in aspeed_peci_xfer()
264 dev_dbg(priv->dev, "no valid response, status: %#02x\n", priv->status); in aspeed_peci_xfer()
265 return -EIO; in aspeed_peci_xfer()
268 spin_unlock_irq(&priv->lock); in aspeed_peci_xfer()
272 * buffer size is multiple of 4-bytes. in aspeed_peci_xfer()
276 for (i = 0; i < req->rx.len; i += 4) { in aspeed_peci_xfer()
278 u32 rx_data = readl(priv->base + reg); in aspeed_peci_xfer()
280 put_unaligned_le32(rx_data, &req->rx.buf[i]); in aspeed_peci_xfer()
284 print_hex_dump_bytes("RX : ", DUMP_PREFIX_NONE, req->rx.buf, req->rx.len); in aspeed_peci_xfer()
294 spin_lock(&priv->lock); in aspeed_peci_irq_handler()
295 status = readl(priv->base + ASPEED_PECI_INT_STS); in aspeed_peci_irq_handler()
296 writel(status, priv->base + ASPEED_PECI_INT_STS); in aspeed_peci_irq_handler()
297 priv->status |= (status & ASPEED_PECI_INT_MASK); in aspeed_peci_irq_handler()
304 complete(&priv->xfer_complete); in aspeed_peci_irq_handler()
306 writel(0, priv->base + ASPEED_PECI_CMD); in aspeed_peci_irq_handler()
308 spin_unlock(&priv->lock); in aspeed_peci_irq_handler()
320 diff = abs(rate - ASPEED_PECI_CLK_DIV1(i) * ASPEED_PECI_CLK_DIV2(j)); in clk_aspeed_peci_find_div_values()
346 struct aspeed_peci *aspeed_peci = peci_clk->aspeed_peci; in clk_aspeed_peci_set_rate()
353 val = readl(aspeed_peci->base + ASPEED_PECI_CTRL); in clk_aspeed_peci_set_rate()
355 writel(val, aspeed_peci->base + ASPEED_PECI_CTRL); in clk_aspeed_peci_set_rate()
359 writel(val, aspeed_peci->base + ASPEED_PECI_TIMING_NEGOTIATION); in clk_aspeed_peci_set_rate()
375 struct aspeed_peci *aspeed_peci = peci_clk->aspeed_peci; in clk_aspeed_peci_recalc_rate()
379 reg = readl(aspeed_peci->base + ASPEED_PECI_TIMING_NEGOTIATION); in clk_aspeed_peci_recalc_rate()
386 reg = readl(aspeed_peci->base + ASPEED_PECI_CTRL); in clk_aspeed_peci_recalc_rate()
401 * PECI HW contains a clock divider which is a combination of:
406 * The resulting frequency is used by PECI Controller to drive the PECI bus to
430 return ERR_PTR(-ENOMEM); in devm_aspeed_peci_register_clk_div()
432 peci_clk->hw.init = &init; in devm_aspeed_peci_register_clk_div()
433 peci_clk->aspeed_peci = priv; in devm_aspeed_peci_register_clk_div()
435 ret = devm_clk_hw_register(dev, &peci_clk->hw); in devm_aspeed_peci_register_clk_div()
439 return peci_clk->hw.clk; in devm_aspeed_peci_register_clk_div()
463 aspeed_peci_property_sanitize(priv->dev, "clock-frequency", in aspeed_peci_property_setup()
465 ASPEED_PECI_CLK_FREQUENCY_DEFAULT, &priv->clk_frequency); in aspeed_peci_property_setup()
466 aspeed_peci_property_sanitize(priv->dev, "cmd-timeout-ms", in aspeed_peci_property_setup()
468 ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT, &priv->cmd_timeout_ms); in aspeed_peci_property_setup()
514 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); in aspeed_peci_probe()
516 return -ENOMEM; in aspeed_peci_probe()
518 priv->dev = &pdev->dev; in aspeed_peci_probe()
519 dev_set_drvdata(priv->dev, priv); in aspeed_peci_probe()
521 priv->base = devm_platform_ioremap_resource(pdev, 0); in aspeed_peci_probe()
522 if (IS_ERR(priv->base)) in aspeed_peci_probe()
523 return PTR_ERR(priv->base); in aspeed_peci_probe()
525 priv->irq = platform_get_irq(pdev, 0); in aspeed_peci_probe()
526 if (priv->irq < 0) in aspeed_peci_probe()
527 return priv->irq; in aspeed_peci_probe()
529 ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler, in aspeed_peci_probe()
530 0, "peci-aspeed", priv); in aspeed_peci_probe()
534 init_completion(&priv->xfer_complete); in aspeed_peci_probe()
535 spin_lock_init(&priv->lock); in aspeed_peci_probe()
537 priv->rst = devm_reset_control_get(&pdev->dev, NULL); in aspeed_peci_probe()
538 if (IS_ERR(priv->rst)) in aspeed_peci_probe()
539 return dev_err_probe(priv->dev, PTR_ERR(priv->rst), in aspeed_peci_probe()
542 ret = devm_aspeed_peci_reset_control_deassert(priv->dev, priv->rst); in aspeed_peci_probe()
544 return dev_err_probe(priv->dev, ret, "cannot deassert reset control\n"); in aspeed_peci_probe()
550 ref_clk = devm_clk_get(priv->dev, NULL); in aspeed_peci_probe()
552 return dev_err_probe(priv->dev, PTR_ERR(ref_clk), "failed to get ref clock\n"); in aspeed_peci_probe()
554 priv->clk = devm_aspeed_peci_register_clk_div(priv->dev, ref_clk, priv); in aspeed_peci_probe()
555 if (IS_ERR(priv->clk)) in aspeed_peci_probe()
556 return dev_err_probe(priv->dev, PTR_ERR(priv->clk), "cannot register clock\n"); in aspeed_peci_probe()
558 ret = clk_set_rate(priv->clk, priv->clk_frequency); in aspeed_peci_probe()
560 return dev_err_probe(priv->dev, ret, "cannot set clock frequency\n"); in aspeed_peci_probe()
562 ret = devm_aspeed_peci_clk_enable(priv->dev, priv->clk); in aspeed_peci_probe()
564 return dev_err_probe(priv->dev, ret, "failed to enable clock\n"); in aspeed_peci_probe()
568 controller = devm_peci_controller_add(priv->dev, &aspeed_ops); in aspeed_peci_probe()
570 return dev_err_probe(priv->dev, PTR_ERR(controller), in aspeed_peci_probe()
571 "failed to add aspeed peci controller\n"); in aspeed_peci_probe()
573 priv->controller = controller; in aspeed_peci_probe()
579 { .compatible = "aspeed,ast2400-peci", },
580 { .compatible = "aspeed,ast2500-peci", },
581 { .compatible = "aspeed,ast2600-peci", },
589 .name = "peci-aspeed",
597 MODULE_DESCRIPTION("ASPEED PECI driver");
599 MODULE_IMPORT_NS(PECI);