Skip to content

Commit cd3d647

Browse files
committed
Merge tag 'i3c/for-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux
Pull i3c updates from Alexandre Belloni: "This adds support for the I3C HCI controller of the AMD SoC which as expected requires quirks. Also fixes for the other drivers, including rate selection fixes for svc. Core: - allow adjusting first broadcast address speed Drivers: - cdns: few fixes - mipi-i3c-hci: Add AMD SoC I3C controller support and quirks, fix get_i3c_mode - svc: adjust rates, fix race condition" * tag 'i3c/for-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux: i3c: master: svc: Fix use after free vulnerability in svc_i3c_master Driver Due to Race Condition i3c: master: cdns: Fix use after free vulnerability in cdns_i3c_master Driver Due to Race Condition i3c: master: svc: adjust SDR according to i3c spec i3c: master: svc: use slow speed for first broadcast address i3c: master: support to adjust first broadcast address speed i3c/master: cmd_v1: Fix the rule for getting i3c mode i3c: master: cdns: fix module autoloading i3c: mipi-i3c-hci: Add a quirk to set Response buffer threshold i3c: mipi-i3c-hci: Add a quirk to set timing parameters i3c: mipi-i3c-hci: Relocate helper macros to HCI header file i3c: mipi-i3c-hci: Add a quirk to set PIO mode i3c: mipi-i3c-hci: Read HC_CONTROL_PIO_MODE only after i3c hci v1.1 i3c: mipi-i3c-hci: Add AMDI5017 ACPI ID to the I3C Support List
2 parents ba0c0cb + 6185072 commit cd3d647

File tree

9 files changed

+193
-26
lines changed

9 files changed

+193
-26
lines changed

drivers/i3c/master.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1868,6 +1868,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
18681868
goto err_bus_cleanup;
18691869
}
18701870

1871+
if (master->ops->set_speed) {
1872+
ret = master->ops->set_speed(master, I3C_OPEN_DRAIN_SLOW_SPEED);
1873+
if (ret)
1874+
goto err_bus_cleanup;
1875+
}
1876+
18711877
/*
18721878
* Reset all dynamic address that may have been assigned before
18731879
* (assigned by the bootloader for example).
@@ -1876,6 +1882,12 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
18761882
if (ret && ret != I3C_ERROR_M2)
18771883
goto err_bus_cleanup;
18781884

1885+
if (master->ops->set_speed) {
1886+
master->ops->set_speed(master, I3C_OPEN_DRAIN_NORMAL_SPEED);
1887+
if (ret)
1888+
goto err_bus_cleanup;
1889+
}
1890+
18791891
/* Disable all slave events before starting DAA. */
18801892
ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR,
18811893
I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR |

drivers/i3c/master/i3c-master-cdns.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,6 +1562,7 @@ static const struct of_device_id cdns_i3c_master_of_ids[] = {
15621562
{ .compatible = "cdns,i3c-master", .data = &cdns_i3c_devdata },
15631563
{ /* sentinel */ },
15641564
};
1565+
MODULE_DEVICE_TABLE(of, cdns_i3c_master_of_ids);
15651566

15661567
static int cdns_i3c_master_probe(struct platform_device *pdev)
15671568
{
@@ -1666,6 +1667,7 @@ static void cdns_i3c_master_remove(struct platform_device *pdev)
16661667
{
16671668
struct cdns_i3c_master *master = platform_get_drvdata(pdev);
16681669

1670+
cancel_work_sync(&master->hj_work);
16691671
i3c_master_unregister(&master->base);
16701672

16711673
clk_disable_unprepare(master->sysclk);

drivers/i3c/master/mipi-i3c-hci/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
obj-$(CONFIG_MIPI_I3C_HCI) += mipi-i3c-hci.o
44
mipi-i3c-hci-y := core.o ext_caps.o pio.o dma.o \
55
cmd_v1.o cmd_v2.o \
6-
dat_v1.o dct_v1.o
6+
dat_v1.o dct_v1.o \
7+
hci_quirks.o

drivers/i3c/master/mipi-i3c-hci/cmd_v1.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,17 +123,15 @@ static enum hci_cmd_mode get_i3c_mode(struct i3c_hci *hci)
123123
{
124124
struct i3c_bus *bus = i3c_master_get_bus(&hci->master);
125125

126-
if (bus->scl_rate.i3c >= 12500000)
127-
return MODE_I3C_SDR0;
128126
if (bus->scl_rate.i3c > 8000000)
129-
return MODE_I3C_SDR1;
127+
return MODE_I3C_SDR0;
130128
if (bus->scl_rate.i3c > 6000000)
131-
return MODE_I3C_SDR2;
129+
return MODE_I3C_SDR1;
132130
if (bus->scl_rate.i3c > 4000000)
133-
return MODE_I3C_SDR3;
131+
return MODE_I3C_SDR2;
134132
if (bus->scl_rate.i3c > 2000000)
135-
return MODE_I3C_SDR4;
136-
return MODE_I3C_Fm_FmP;
133+
return MODE_I3C_SDR3;
134+
return MODE_I3C_SDR4;
137135
}
138136

139137
static enum hci_cmd_mode get_i2c_mode(struct i3c_hci *hci)

drivers/i3c/master/mipi-i3c-hci/core.c

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include <linux/errno.h>
1313
#include <linux/i3c/master.h>
1414
#include <linux/interrupt.h>
15-
#include <linux/io.h>
1615
#include <linux/iopoll.h>
1716
#include <linux/module.h>
1817
#include <linux/platform_device.h>
@@ -27,11 +26,6 @@
2726
* Host Controller Capabilities and Operation Registers
2827
*/
2928

30-
#define reg_read(r) readl(hci->base_regs + (r))
31-
#define reg_write(r, v) writel(v, hci->base_regs + (r))
32-
#define reg_set(r, v) reg_write(r, reg_read(r) | (v))
33-
#define reg_clear(r, v) reg_write(r, reg_read(r) & ~(v))
34-
3529
#define HCI_VERSION 0x00 /* HCI Version (in BCD) */
3630

3731
#define HC_CONTROL 0x04
@@ -152,6 +146,10 @@ static int i3c_hci_bus_init(struct i3c_master_controller *m)
152146
if (ret)
153147
return ret;
154148

149+
/* Set RESP_BUF_THLD to 0(n) to get 1(n+1) response */
150+
if (hci->quirks & HCI_QUIRK_RESP_BUF_THLD)
151+
amd_set_resp_buf_thld(hci);
152+
155153
reg_set(HC_CONTROL, HC_CONTROL_BUS_ENABLE);
156154
DBG("HC_CONTROL = %#x", reg_read(HC_CONTROL));
157155

@@ -630,8 +628,8 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id)
630628

631629
static int i3c_hci_init(struct i3c_hci *hci)
632630
{
631+
bool size_in_dwords, mode_selector;
633632
u32 regval, offset;
634-
bool size_in_dwords;
635633
int ret;
636634

637635
/* Validate HCI hardware version */
@@ -753,10 +751,17 @@ static int i3c_hci_init(struct i3c_hci *hci)
753751
return -EINVAL;
754752
}
755753

754+
mode_selector = hci->version_major > 1 ||
755+
(hci->version_major == 1 && hci->version_minor > 0);
756+
757+
/* Quirk for HCI_QUIRK_PIO_MODE on AMD platforms */
758+
if (hci->quirks & HCI_QUIRK_PIO_MODE)
759+
hci->RHS_regs = NULL;
760+
756761
/* Try activating DMA operations first */
757762
if (hci->RHS_regs) {
758763
reg_clear(HC_CONTROL, HC_CONTROL_PIO_MODE);
759-
if (reg_read(HC_CONTROL) & HC_CONTROL_PIO_MODE) {
764+
if (mode_selector && (reg_read(HC_CONTROL) & HC_CONTROL_PIO_MODE)) {
760765
dev_err(&hci->master.dev, "PIO mode is stuck\n");
761766
ret = -EIO;
762767
} else {
@@ -768,7 +773,7 @@ static int i3c_hci_init(struct i3c_hci *hci)
768773
/* If no DMA, try PIO */
769774
if (!hci->io && hci->PIO_regs) {
770775
reg_set(HC_CONTROL, HC_CONTROL_PIO_MODE);
771-
if (!(reg_read(HC_CONTROL) & HC_CONTROL_PIO_MODE)) {
776+
if (mode_selector && !(reg_read(HC_CONTROL) & HC_CONTROL_PIO_MODE)) {
772777
dev_err(&hci->master.dev, "DMA mode is stuck\n");
773778
ret = -EIO;
774779
} else {
@@ -784,6 +789,10 @@ static int i3c_hci_init(struct i3c_hci *hci)
784789
return ret;
785790
}
786791

792+
/* Configure OD and PP timings for AMD platforms */
793+
if (hci->quirks & HCI_QUIRK_OD_PP_TIMING)
794+
amd_set_od_pp_timing(hci);
795+
787796
return 0;
788797
}
789798

@@ -803,6 +812,8 @@ static int i3c_hci_probe(struct platform_device *pdev)
803812
/* temporary for dev_printk's, to be replaced in i3c_master_register */
804813
hci->master.dev.init_name = dev_name(&pdev->dev);
805814

815+
hci->quirks = (unsigned long)device_get_match_data(&pdev->dev);
816+
806817
ret = i3c_hci_init(hci);
807818
if (ret)
808819
return ret;
@@ -834,12 +845,19 @@ static const __maybe_unused struct of_device_id i3c_hci_of_match[] = {
834845
};
835846
MODULE_DEVICE_TABLE(of, i3c_hci_of_match);
836847

848+
static const struct acpi_device_id i3c_hci_acpi_match[] = {
849+
{ "AMDI5017", HCI_QUIRK_PIO_MODE | HCI_QUIRK_OD_PP_TIMING | HCI_QUIRK_RESP_BUF_THLD },
850+
{}
851+
};
852+
MODULE_DEVICE_TABLE(acpi, i3c_hci_acpi_match);
853+
837854
static struct platform_driver i3c_hci_driver = {
838855
.probe = i3c_hci_probe,
839856
.remove_new = i3c_hci_remove,
840857
.driver = {
841858
.name = "mipi-i3c-hci",
842859
.of_match_table = of_match_ptr(i3c_hci_of_match),
860+
.acpi_match_table = i3c_hci_acpi_match,
843861
},
844862
};
845863
module_platform_driver(i3c_hci_driver);

drivers/i3c/master/mipi-i3c-hci/hci.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#ifndef HCI_H
1111
#define HCI_H
1212

13+
#include <linux/io.h>
1314

1415
/* Handy logging macro to save on line length */
1516
#define DBG(x, ...) pr_devel("%s: " x "\n", __func__, ##__VA_ARGS__)
@@ -26,6 +27,10 @@
2627
#define W2_BIT_(x) BIT((x) - 64)
2728
#define W3_BIT_(x) BIT((x) - 96)
2829

30+
#define reg_read(r) readl(hci->base_regs + (r))
31+
#define reg_write(r, v) writel(v, hci->base_regs + (r))
32+
#define reg_set(r, v) reg_write(r, reg_read(r) | (v))
33+
#define reg_clear(r, v) reg_write(r, reg_read(r) & ~(v))
2934

3035
struct hci_cmd_ops;
3136

@@ -135,11 +140,16 @@ struct i3c_hci_dev_data {
135140

136141
/* list of quirks */
137142
#define HCI_QUIRK_RAW_CCC BIT(1) /* CCC framing must be explicit */
143+
#define HCI_QUIRK_PIO_MODE BIT(2) /* Set PIO mode for AMD platforms */
144+
#define HCI_QUIRK_OD_PP_TIMING BIT(3) /* Set OD and PP timings for AMD platforms */
145+
#define HCI_QUIRK_RESP_BUF_THLD BIT(4) /* Set resp buf thld to 0 for AMD platforms */
138146

139147

140148
/* global functions */
141149
void mipi_i3c_hci_resume(struct i3c_hci *hci);
142150
void mipi_i3c_hci_pio_reset(struct i3c_hci *hci);
143151
void mipi_i3c_hci_dct_index_reset(struct i3c_hci *hci);
152+
void amd_set_od_pp_timing(struct i3c_hci *hci);
153+
void amd_set_resp_buf_thld(struct i3c_hci *hci);
144154

145155
#endif
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* I3C HCI Quirks
4+
*
5+
* Copyright 2024 Advanced Micro Devices, Inc.
6+
*
7+
* Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
8+
* Guruvendra Punugupati <Guruvendra.Punugupati@amd.com>
9+
*/
10+
11+
#include <linux/i3c/master.h>
12+
#include "hci.h"
13+
14+
/* Timing registers */
15+
#define HCI_SCL_I3C_OD_TIMING 0x214
16+
#define HCI_SCL_I3C_PP_TIMING 0x218
17+
#define HCI_SDA_HOLD_SWITCH_DLY_TIMING 0x230
18+
19+
/* Timing values to configure 9MHz frequency */
20+
#define AMD_SCL_I3C_OD_TIMING 0x00cf00cf
21+
#define AMD_SCL_I3C_PP_TIMING 0x00160016
22+
23+
#define QUEUE_THLD_CTRL 0xD0
24+
25+
void amd_set_od_pp_timing(struct i3c_hci *hci)
26+
{
27+
u32 data;
28+
29+
reg_write(HCI_SCL_I3C_OD_TIMING, AMD_SCL_I3C_OD_TIMING);
30+
reg_write(HCI_SCL_I3C_PP_TIMING, AMD_SCL_I3C_PP_TIMING);
31+
data = reg_read(HCI_SDA_HOLD_SWITCH_DLY_TIMING);
32+
/* Configure maximum TX hold time */
33+
data |= W0_MASK(18, 16);
34+
reg_write(HCI_SDA_HOLD_SWITCH_DLY_TIMING, data);
35+
}
36+
37+
void amd_set_resp_buf_thld(struct i3c_hci *hci)
38+
{
39+
u32 data;
40+
41+
data = reg_read(QUEUE_THLD_CTRL);
42+
data = data & ~W0_MASK(15, 8);
43+
reg_write(QUEUE_THLD_CTRL, data);
44+
}

0 commit comments

Comments
 (0)