* Re: [PATCH V4 2/2] pinctrl: bcm: add driver for BCM4908 pinmux
From: Linus Walleij @ 2022-01-25 0:43 UTC (permalink / raw)
To: Rafał Miłecki
Cc: Rob Herring, Álvaro Fernández Rojas, Jonas Gorski,
Randy Dunlap, Florian Fainelli, linux-gpio, devicetree,
bcm-kernel-feedback-list, Andy Shevchenko,
Rafał Miłecki
In-Reply-To: <20220124102243.14912-2-zajec5@gmail.com>
On Mon, Jan 24, 2022 at 11:22 AM Rafał Miłecki <zajec5@gmail.com> wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
>
> BCM4908 has its own pins layout so it needs a custom binding and a Linux
> driver.
>
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
> ---
> V2: Formatting fixes
> Kconfig fix
> Cleanup of #include-s
> Use devm_kasprintf_strarray()
> V3: Bring back OF dependency - required by pinconf_generic_dt_node_to_map()
> V4: Rebased on top of the latest for-next which includes 5.17-rc1 now
Patch applied!
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH] kbuild: unify cmd_copy and cmd_shipped
From: Masahiro Yamada @ 2022-01-25 6:40 UTC (permalink / raw)
To: linux-kbuild
Cc: Masahiro Yamada, Gabriel Krisman Bertazi, Michal Marek,
Michal Simek, Nick Desaulniers, Rob Herring, devicetree,
linux-fsdevel, linux-kernel
cmd_copy and cmd_shipped have similar functionality. The difference is
that cmd_copy uses 'cp' while cmd_shipped 'cat'.
Unify them into cmd_copy because this macro name is more intuitive.
Going forward, cmd_copy will use 'cat' to avoid the permission issue.
I also thought of 'cp --no-preserve=mode' but this option is not
mentioned in the POSIX spec [1], so I am keeping the 'cat' command.
[1]: https://pubs.opengroup.org/onlinepubs/009695299/utilities/cp.html
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
---
arch/microblaze/boot/Makefile | 2 +-
arch/microblaze/boot/dts/Makefile | 2 +-
fs/unicode/Makefile | 2 +-
scripts/Makefile.lib | 12 ++++--------
usr/Makefile | 4 ++--
5 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile
index cff570a71946..2b42c370d574 100644
--- a/arch/microblaze/boot/Makefile
+++ b/arch/microblaze/boot/Makefile
@@ -29,7 +29,7 @@ $(obj)/simpleImage.$(DTB).ub: $(obj)/simpleImage.$(DTB) FORCE
$(call if_changed,uimage)
$(obj)/simpleImage.$(DTB).unstrip: vmlinux FORCE
- $(call if_changed,shipped)
+ $(call if_changed,copy)
$(obj)/simpleImage.$(DTB).strip: vmlinux FORCE
$(call if_changed,strip)
diff --git a/arch/microblaze/boot/dts/Makefile b/arch/microblaze/boot/dts/Makefile
index ef00dd30d19a..b84e2cbb20ee 100644
--- a/arch/microblaze/boot/dts/Makefile
+++ b/arch/microblaze/boot/dts/Makefile
@@ -12,7 +12,7 @@ $(obj)/linked_dtb.o: $(obj)/system.dtb
# Generate system.dtb from $(DTB).dtb
ifneq ($(DTB),system)
$(obj)/system.dtb: $(obj)/$(DTB).dtb
- $(call if_changed,shipped)
+ $(call if_changed,copy)
endif
endif
diff --git a/fs/unicode/Makefile b/fs/unicode/Makefile
index 2f9d9188852b..74ae80fc3a36 100644
--- a/fs/unicode/Makefile
+++ b/fs/unicode/Makefile
@@ -31,7 +31,7 @@ $(obj)/utf8data.c: $(obj)/mkutf8data $(filter %.txt, $(cmd_utf8data)) FORCE
else
$(obj)/utf8data.c: $(src)/utf8data.c_shipped FORCE
- $(call if_changed,shipped)
+ $(call if_changed,copy)
endif
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 79be57fdd32a..40735a3adb54 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -246,20 +246,16 @@ $(foreach m, $(notdir $1), \
$(addprefix $(obj)/, $(foreach s, $3, $($(m:%$(strip $2)=%$(s)))))))
endef
-quiet_cmd_copy = COPY $@
- cmd_copy = cp $< $@
-
-# Shipped files
+# Copy a file
# ===========================================================================
# 'cp' preserves permissions. If you use it to copy a file in read-only srctree,
# the copy would be read-only as well, leading to an error when executing the
# rule next time. Use 'cat' instead in order to generate a writable file.
-
-quiet_cmd_shipped = SHIPPED $@
-cmd_shipped = cat $< > $@
+quiet_cmd_copy = COPY $@
+ cmd_copy = cat $< > $@
$(obj)/%: $(src)/%_shipped
- $(call cmd,shipped)
+ $(call cmd,copy)
# Commands useful for building a boot image
# ===========================================================================
diff --git a/usr/Makefile b/usr/Makefile
index cc0d2824e100..59d9e8b07a01 100644
--- a/usr/Makefile
+++ b/usr/Makefile
@@ -3,7 +3,7 @@
# kbuild file for usr/ - including initramfs image
#
-compress-y := shipped
+compress-y := copy
compress-$(CONFIG_INITRAMFS_COMPRESSION_GZIP) := gzip
compress-$(CONFIG_INITRAMFS_COMPRESSION_BZIP2) := bzip2
compress-$(CONFIG_INITRAMFS_COMPRESSION_LZMA) := lzma
@@ -37,7 +37,7 @@ endif
# .cpio.*, use it directly as an initramfs, and avoid double compression.
ifeq ($(words $(subst .cpio.,$(space),$(ramfs-input))),2)
cpio-data := $(ramfs-input)
-compress-y := shipped
+compress-y := copy
endif
endif
--
2.32.0
^ permalink raw reply related
* Re: [PATCH 0/4] Refactor the PRCI driver to reduce the complexity
From: Zong Li @ 2022-01-25 5:12 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Palmer Dabbelt, Paul Walmsley,
Lee Jones, Rob Herring,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
linux-riscv, linux-clk, linux-kernel@vger.kernel.org List
In-Reply-To: <cover.1642582832.git.zong.li@sifive.com>
On Wed, Jan 19, 2022 at 5:28 PM Zong Li <zong.li@sifive.com> wrote:
>
> This patch set tries to improve the PRCI driver to reduce the
> complexity, we remove the SoCs C files by putting putting all stuff in
> each SoCs header file, and include these SoCs-specific header files in
> core of PRCI. It can also avoid the W=1 kernel build warnings about
> variable defined but not used [-Wunused-const-variable=], like 'commit
> 487dc7bb6a0c ("clk: sifive:fu540-prci: Declare static const variable
> 'prci_clk_fu540' where it's used")' does.
>
> This patch set also contains the dt-bindings and dts change, because
> we change the macro name for fu540 and fu740 by adding the prefix
> respectively.
>
> Thanks all for your review and suggestions.
>
> Zong Li (4):
> dt-bindings: change the macro name of prci in header files and example
> riscv: dts: Change the macro name of prci in each device node
> clk: sifive: Add SoCs prefix in each SoCs-dependent data
> clk: sifive: Move all stuff into SoCs header files from C files
>
> .../devicetree/bindings/gpio/sifive,gpio.yaml | 2 +-
> .../bindings/pci/sifive,fu740-pcie.yaml | 2 +-
> .../bindings/serial/sifive-serial.yaml | 2 +-
> arch/riscv/boot/dts/sifive/fu540-c000.dtsi | 22 +--
> arch/riscv/boot/dts/sifive/fu740-c000.dtsi | 26 ++--
> drivers/clk/sifive/Makefile | 2 +-
> drivers/clk/sifive/fu540-prci.c | 89 ------------
> drivers/clk/sifive/fu540-prci.h | 91 +++++++++++-
> drivers/clk/sifive/fu740-prci.c | 134 ------------------
> drivers/clk/sifive/fu740-prci.h | 130 ++++++++++++++++-
> drivers/clk/sifive/sifive-prci.c | 5 -
> include/dt-bindings/clock/sifive-fu540-prci.h | 8 +-
> include/dt-bindings/clock/sifive-fu740-prci.h | 18 +--
> 13 files changed, 254 insertions(+), 277 deletions(-)
> delete mode 100644 drivers/clk/sifive/fu540-prci.c
> delete mode 100644 drivers/clk/sifive/fu740-prci.c
>
> --
> 2.31.1
>
Hi all, thanks for your review, I'd like to know if anything else can
be improved in this patch, or it might be good enough to be picked up.
Thanks.
^ permalink raw reply
* Re: [PATCH v4 3/3] dmaengine: sf-pdma: Get number of channel by device tree
From: Zong Li @ 2022-01-25 5:08 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Palmer Dabbelt, Rob Herring, Paul Walmsley, Albert Ou,
Krzysztof Kozlowski, Conor Dooley, Bin Meng, Green Wan, Vinod,
dmaengine,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
linux-kernel@vger.kernel.org List, linux-riscv
In-Reply-To: <CANXhq0oTrVMhY19odFHroJKXmW1dROdS5J5YR-osO9uwbr9GKA@mail.gmail.com>
On Fri, Jan 21, 2022 at 6:29 PM Zong Li <zong.li@sifive.com> wrote:
>
> On Fri, Jan 21, 2022 at 4:33 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> >
> > Hi Zong, Palmer,
> >
> > On Fri, Jan 21, 2022 at 3:21 AM Zong Li <zong.li@sifive.com> wrote:
> > > On Fri, Jan 21, 2022 at 2:52 AM Palmer Dabbelt <palmer@dabbelt.com> wrote:
> > > > On Sun, 16 Jan 2022 17:35:28 PST (-0800), zong.li@sifive.com wrote:
> > > > > It currently assumes that there are always four channels, it would
> > > > > cause the error if there is actually less than four channels. Change
> > > > > that by getting number of channel from device tree.
> > > > >
> > > > > For backwards-compatible, it uses the default value (i.e. 4) when there
> > > > > is no 'dma-channels' information in dts.
> > > >
> > > > Some of the same wording issues here as those I pointed out in the DT
> > > > bindings patch.
> > > >
> > > > > Signed-off-by: Zong Li <zong.li@sifive.com>
> >
> > > > > --- a/drivers/dma/sf-pdma/sf-pdma.c
> > > > > +++ b/drivers/dma/sf-pdma/sf-pdma.c
> > > > > @@ -482,9 +482,7 @@ static void sf_pdma_setup_chans(struct sf_pdma *pdma)
> > > > > static int sf_pdma_probe(struct platform_device *pdev)
> > > > > {
> > > > > struct sf_pdma *pdma;
> > > > > - struct sf_pdma_chan *chan;
> > > > > struct resource *res;
> > > > > - int len, chans;
> > > > > int ret;
> > > > > const enum dma_slave_buswidth widths =
> > > > > DMA_SLAVE_BUSWIDTH_1_BYTE | DMA_SLAVE_BUSWIDTH_2_BYTES |
> > > > > @@ -492,13 +490,21 @@ static int sf_pdma_probe(struct platform_device *pdev)
> > > > > DMA_SLAVE_BUSWIDTH_16_BYTES | DMA_SLAVE_BUSWIDTH_32_BYTES |
> > > > > DMA_SLAVE_BUSWIDTH_64_BYTES;
> > > > >
> > > > > - chans = PDMA_NR_CH;
> > > > > - len = sizeof(*pdma) + sizeof(*chan) * chans;
> > > > > - pdma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
> > > > > + pdma = devm_kzalloc(&pdev->dev, sizeof(*pdma), GFP_KERNEL);
> > > > > if (!pdma)
> > > > > return -ENOMEM;
> > > > >
> > > > > - pdma->n_chans = chans;
> > > > > + ret = of_property_read_u32(pdev->dev.of_node, "dma-channels",
> > > > > + &pdma->n_chans);
> > > > > + if (ret) {
> > > > > + dev_notice(&pdev->dev, "set number of channels to default value: 4\n");
> > > > > + pdma->n_chans = PDMA_MAX_NR_CH;
> > > > > + }
> > > > > +
> > > > > + if (pdma->n_chans > PDMA_MAX_NR_CH) {
> > > > > + dev_err(&pdev->dev, "the number of channels exceeds the maximum\n");
> > > > > + return -EINVAL;
> > > >
> > > > Can we get away with just using only the number of channels the driver
> > > > actually supports? ie, just never sending an op to the channels above
> > > > MAX_NR_CH? That should leave us with nothing to track.
> >
> > In theory we can...
> >
> > > It might be a bit like when pdma->n_chans is bigger than the maximum,
> > > set the pdma->chans to PDMA_MAX_NR_CH, then we could ensure that we
> > > don't access the channels above the maximum. If I understand
> > > correctly, I gave the similar thought in the thread of v2 patch, and
> > > there are some discussions on that, but this way seems to lead to
> > > hard-to-track problems.
> >
> > ... but that would mean that when a new variant appears that supports
> > more channels, no error is printed, and people might not notice
> > immediately that the higher channels are never used.
> >
>
> I guess people might need to follow the dt-bindings, so they couldn't
> specify the number of channels to the value which is more than
> maximum. But as you mentioned, if people don't notice that and specify
> it more than maximum, they wouldn't be aware that the higher channels
> are never used. It seems to me that we could keep returning the error
> there, or show a warning message and use PDMA_MAX_NR_CH in that
> situation, both looks good to me.
>
Hi all, thank you for the review, I'd like to prepare the next version
patch, if current implementation of this part is ok to you, I will
keep it in the next version. Please let me know if anything can be
improved. Thanks
> > Gr{oetje,eeting}s,
> >
> > Geert
> >
> > --
> > Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> >
> > In personal conversations with technical people, I call myself a hacker. But
> > when I'm talking to journalists I just say "programmer" or something like that.
> > -- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v3 3/4] dt-bindings: hwmon: Add binding for max6639
From: Guenter Roeck @ 2022-01-25 5:08 UTC (permalink / raw)
To: Marcello Sylvester Bauer
Cc: linux-hwmon, Patrick Rudolph, Jean Delvare, Rob Herring,
Roland Stigge, devicetree
In-Reply-To: <24e812dc80983ce20cd51a446c4f6d4a1db7da37.1642585539.git.sylv@sylv.io>
On Wed, Jan 19, 2022 at 10:53:54AM +0100, Marcello Sylvester Bauer wrote:
> Add Devicetree binding documentation for Maxim MAX6639 temperature
> monitor with PWM fan-speed controller.
>
> The devicetree documentation for the SD3078 device tree.
>
> Signed-off-by: Marcello Sylvester Bauer <sylv@sylv.io>
> ---
> .../bindings/hwmon/maxim,max6639.yaml | 112 ++++++++++++++++++
> 1 file changed, 112 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml
>
> diff --git a/Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml b/Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml
> new file mode 100644
> index 000000000000..7093cbeba44b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/maxim,max6639.yaml
> @@ -0,0 +1,112 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +
> +$id: http://devicetree.org/schemas/hwmon/maxim,max6639.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Maxim max6639
> +
> +maintainers:
> + - Roland Stigge <stigge@antcom.de>
> +
> +description: |
> + The MAX6639 is a 2-channel temperature monitor with dual, automatic, PWM
> + fan-speed controller. It monitors its own temperature and one external
> + diode-connected transistor or the temperatures of two external diode-connected
> + transistors, typically available in CPUs, FPGAs, or GPUs.
> +
> + Datasheets:
> + https://datasheets.maximintegrated.com/en/ds/MAX6639-MAX6639F.pdf
> +
> +properties:
> + compatible:
> + enum:
> + - maxim,max6639
> +
> + reg:
> + maxItems: 1
> +
> + '#address-cells':
> + const: 1
> +
> + '#size-cells':
> + const: 0
> +
> +required:
> + - compatible
> + - reg
> + - "channel@0"
> + - "channel@1"
> +
> +additionalProperties: false
> +
> +patternProperties:
> + "^channel@[0-1]$":
> + type: object
> + description: |
> + Represents the two fans and their specific configuration.
> +
> + properties:
> + reg:
> + description: |
> + The fan number.
> + items:
> + minimum: 0
> + maximum: 1
> +
> + pwm-polarity:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [0, 1]
> + description:
> + PWM output is low at 100% duty cycle when this bit is set to zero. PWM
> + output is high at 100% duty cycle when this bit is set to 1.
> +
> + pulses-per-revolution:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [1, 2, 3, 4]
> + description:
> + Value specifying the number of pulses per revolution of the controlled
> + FAN.
> +
I think the above two properties should be optional.
pulses-per-revolution is 2 for almost all fans out there,
and pwm polarity is positive almost all the time.
> + rpm-range:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [2000, 4000, 8000, 16000]
> + description:
> + Scales the tachometer counter by setting the maximum (full-scale) value
> + of the RPM range.
> +
Isn't this the maximum rpm ? Using the term "range" seems to be
a bit misleading.
> + required:
> + - reg
> + - pwm-polarity
> + - pulses-per-revolution
> + - rpm-range
> +
> +examples:
> + - |
> + i2c {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + max6639@10 {
> + compatible = "maxim,max6639";
> + reg = <0x10>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + channel@0 {
> + reg = <0x0>;
> + pwm-polarity = <1>;
> + pulses-per-revolution = <2>;
> + rpm-range = <4000>;
> + };
> +
> + channel@1 {
> + reg = <0x1>;
> + pwm-polarity = <1>;
> + pulses-per-revolution = <2>;
> + rpm-range = <4000>;
> + };
> + };
> + };
> +...
^ permalink raw reply
* Re: [PATCH v2] dt-bindings: PCI: ti,j721e: Add device id for J721S2
From: Aswath Govindraju @ 2022-01-25 6:36 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Vignesh Raghavendra, Nishanth Menon, Kishon Vijay Abraham I,
Rob Herring, linux-pci, devicetree, linux-kernel
In-Reply-To: <20211130035608.13492-1-a-govindraju@ti.com>
Hi Bjorn,
On 30/11/21 9:26 am, Aswath Govindraju wrote:
> Document the device id of J721S2 SoC.
>
> Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
> ---
>
May I know if this patch can be picked up?
Thanks,
Aswath
> changes since v1:
> - changed (oneOf, items) into enum
>
> .../devicetree/bindings/pci/ti,j721e-pci-host.yaml | 12 +++++-------
> 1 file changed, 5 insertions(+), 7 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
> index cc900202df29..41df8f1c2d4c 100644
> --- a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
> +++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
> @@ -64,13 +64,11 @@ properties:
> const: 0x104c
>
> device-id:
> - oneOf:
> - - items:
> - - const: 0xb00d
> - - items:
> - - const: 0xb00f
> - - items:
> - - const: 0xb010
> + enum:
> + - 0xb00d
> + - 0xb00f
> + - 0xb010
> + - 0xb013
>
> msi-map: true
>
>
^ permalink raw reply
* Re: [PATCH v9 2/3] dt-bindings: pinctrl: mt8195: Add mediatek,drive-strength-adv property
From: Tinghan Shen @ 2022-01-25 6:21 UTC (permalink / raw)
To: Matthias Brugger, Rob Herring, Linus Walleij,
AngeloGioacchino Del Regno, David Matlack, Jing Zhang,
Marc Zyngier, Bartosz Golaszewski, Sean Wang
Cc: devicetree, linux-kernel, linux-gpio, linux-arm-kernel,
linux-mediatek, Project_Global_Chrome_Upstream_Group, ryder.lee,
wenst, chunfeng.yun
In-Reply-To: <18f7a647-6153-6d38-dff1-727b9592b01e@gmail.com>
On Thu, 2022-01-13 at 17:31 +0100, Matthias Brugger wrote:
> [dopping Maciej, Paolo and Sean Christopherson]
>
> On 12/01/2022 12:47, Tinghan Shen wrote:
> > Extend driving support for I2C pins on SoC mt8195.
> > This property is already documented in mediatek,mt8183-pinctrl.yaml.
> >
> > Signed-off-by: Tinghan Shen <tinghan.shen@mediatek.com>
> > Reviewed-by: Rob Herring <robh@kernel.org>
>
> Looks good to me. Linus please let me know when you are queuing this patch and
> I'll take the rest of the series. Another option is, that you provide an
> Acked-by and I can take the whole set through my branch.
>
> Regards,
> Matthias
Hi Matthias,
I want to send next version to update the CC list of this series, but I'm not sure
whether this will break the conversation between you and Linus.
Is it ok to send next version? or waiting the response?
Best regards,
TingHan
>
> > ---
> > .../bindings/pinctrl/pinctrl-mt8195.yaml | 35 +++++++++++++++++++
> > 1 file changed, 35 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8195.yaml
> > b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8195.yaml
> > index 328ea59c5466..4db4899af6b1 100644
> > --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8195.yaml
> > +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt8195.yaml
> > @@ -98,6 +98,32 @@ patternProperties:
> > drive-strength:
> > enum: [2, 4, 6, 8, 10, 12, 14, 16]
> >
> > + mediatek,drive-strength-adv:
> > + description: |
> > + Describe the specific driving setup property.
> > + For I2C pins, the existing generic driving setup can only support
> > + 2/4/6/8/10/12/14/16mA driving. But in specific driving setup, they
> > + can support 0.125/0.25/0.5/1mA adjustment. If we enable specific
> > + driving setup, the existing generic setup will be disabled.
> > + The specific driving setup is controlled by E1E0EN.
> > + When E1=0/E0=0, the strength is 0.125mA.
> > + When E1=0/E0=1, the strength is 0.25mA.
> > + When E1=1/E0=0, the strength is 0.5mA.
> > + When E1=1/E0=1, the strength is 1mA.
> > + EN is used to enable or disable the specific driving setup.
> > + Valid arguments are described as below:
> > + 0: (E1, E0, EN) = (0, 0, 0)
> > + 1: (E1, E0, EN) = (0, 0, 1)
> > + 2: (E1, E0, EN) = (0, 1, 0)
> > + 3: (E1, E0, EN) = (0, 1, 1)
> > + 4: (E1, E0, EN) = (1, 0, 0)
> > + 5: (E1, E0, EN) = (1, 0, 1)
> > + 6: (E1, E0, EN) = (1, 1, 0)
> > + 7: (E1, E0, EN) = (1, 1, 1)
> > + So the valid arguments are from 0 to 7.
> > + $ref: /schemas/types.yaml#/definitions/uint32
> > + enum: [0, 1, 2, 3, 4, 5, 6, 7]
> > +
> > bias-pull-down:
> > description: |
> > For pull down type is normal, it don't need add RSEL & R1R0 define
> > @@ -268,4 +294,13 @@ examples:
> > bias-pull-down;
> > };
> > };
> > +
> > + i2c0-pins {
> > + pins {
> > + pinmux = <PINMUX_GPIO8__FUNC_SDA0>,
> > + <PINMUX_GPIO9__FUNC_SCL0>;
> > + bias-disable;
> > + mediatek,drive-strength-adv = <7>;
> > + };
> > + };
> > };
> >
^ permalink raw reply
* Re: [PATCH net-next 4/4] dt-binding: can: rcar-can: include common CAN controller bindings
From: Rob Herring @ 2022-01-25 4:14 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: Rob Herring, linux-can, Yoshihiro Shimoda, devicetree,
lrich Hecht
In-Reply-To: <20220124220653.3477172-5-mkl@pengutronix.de>
On Mon, 24 Jan 2022 23:06:53 +0100, Marc Kleine-Budde wrote:
> Since commit
>
> | 1f9234401ce0 ("dt-bindings: can: add can-controller.yaml")
>
> there is a common CAN controller binding. Add this to the rcar-can
> binding.
>
> Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> Cc: lrich Hecht <uli+renesas@fpond.eu>
> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
> ---
> .../devicetree/bindings/net/can/renesas,rcar-can.yaml | 3 +++
> 1 file changed, 3 insertions(+)
>
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
./Documentation/devicetree/bindings/net/can/renesas,rcar-can.yaml:102:1: [error] duplication of key "allOf" in mapping (key-duplicates)
dtschema/dtc warnings/errors:
make[1]: *** Deleting file 'Documentation/devicetree/bindings/net/can/renesas,rcar-can.example.dts'
Documentation/devicetree/bindings/net/can/renesas,rcar-can.yaml: found duplicate key "allOf" with value "[]" (original value: "[]")
make[1]: *** [Documentation/devicetree/bindings/Makefile:25: Documentation/devicetree/bindings/net/can/renesas,rcar-can.example.dts] Error 1
make[1]: *** Waiting for unfinished jobs....
Traceback (most recent call last):
File "/usr/local/bin/dt-doc-validate", line 25, in check_doc
testtree = dtschema.load(filename, line_number=line_number)
File "/usr/local/lib/python3.8/dist-packages/dtschema/lib.py", line 661, in load
return yaml.load(f.read())
File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/main.py", line 434, in load
return constructor.get_single_data()
File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/constructor.py", line 121, in get_single_data
return self.construct_document(node)
File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/constructor.py", line 131, in construct_document
for _dummy in generator:
File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/constructor.py", line 674, in construct_yaml_map
value = self.construct_mapping(node)
File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/constructor.py", line 445, in construct_mapping
return BaseConstructor.construct_mapping(self, node, deep=deep)
File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/constructor.py", line 263, in construct_mapping
if self.check_mapping_key(node, key_node, mapping, key, value):
File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/constructor.py", line 294, in check_mapping_key
raise DuplicateKeyError(*args)
ruamel.yaml.constructor.DuplicateKeyError: while constructing a mapping
in "<unicode string>", line 4, column 1
found duplicate key "allOf" with value "[]" (original value: "[]")
in "<unicode string>", line 102, column 1
To suppress this check see:
http://yaml.readthedocs.io/en/latest/api.html#duplicate-keys
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/bin/dt-doc-validate", line 70, in <module>
ret = check_doc(f)
File "/usr/local/bin/dt-doc-validate", line 30, in check_doc
print(filename + ":", exc.path[-1], exc.message, file=sys.stderr)
AttributeError: 'DuplicateKeyError' object has no attribute 'path'
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/net/can/renesas,rcar-can.yaml: ignoring, error parsing file
make: *** [Makefile:1398: dt_binding_check] Error 2
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/patch/1583769
This check can fail if there are any dependencies. The base for a patch
series is generally the most recent rc1.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit.
^ permalink raw reply
* Re: [PATCH v2] arm64: dts: qcom: sm8350: Correct UFS symbol clocks
From: Eric Biggers @ 2022-01-25 5:50 UTC (permalink / raw)
To: Bjorn Andersson; +Cc: Vinod Koul, linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20211222162058.3418902-1-bjorn.andersson@linaro.org>
On Wed, Dec 22, 2021 at 08:20:58AM -0800, Bjorn Andersson wrote:
> The introduction of '9a61f813fcc8 ("clk: qcom: regmap-mux: fix parent
> clock lookup")' broke UFS support on SM8350.
>
> The cause for this is that the symbol clocks have a specified rate in
> the "freq-table-hz" table in the UFS node, which causes the UFS code to
> request a rate change, for which the "bi_tcxo" happens to provide the
> closest rate. Prior to the change in regmap-mux it was determined
> (incorrectly) that no change was needed and everything worked.
>
> The rates of 75 and 300MHz matches the documentation for the symbol
> clocks, but we don't represent the parent clocks today. So let's mimic
> the configuration found in other platforms, by omitting the rate for the
> symbol clocks as well to avoid the rate change.
>
> While at it also fill in the dummy symbol clocks that was dropped from
> the GCC driver as it was upstreamed.
>
> Fixes: 59c7cf814783 ("arm64: dts: qcom: sm8350: Add UFS nodes")
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
Tested-by: Eric Biggers <ebiggers@google.com>
This was sent out over a month ago. Can it be applied? It is annoying having
master as well as v5.16 be broken on SM8350.
- Eric
^ permalink raw reply
* Re: [PATCH 0/3] arm64: dts: meson: add BL32 reserved region to Beelink g12b devices
From: Christian Hewitt @ 2022-01-25 4:03 UTC (permalink / raw)
To: Kevin Hilman
Cc: Rob Herring, Mark Rutland, Neil Armstrong, devicetree,
linux-arm-kernel, linux-amlogic, linux-kernel, Furkan Kardame
In-Reply-To: <7h7daoyka3.fsf@baylibre.com>
>
> On 25 Jan 2022, at 12:02 am, Kevin Hilman <khilman@baylibre.com> wrote:
>
> Christian Hewitt <christianshewitt@gmail.com> writes:
>
>> This resolves a long-running issue where Beelink GT-King/Pro and
>> GS-King-X wedge on boot or shortly after when booting from vendor
>> u-boot. In some distros the issue is often reported as triggered
>> by large file transfers to/from USB or SD cards. Reserving the
>> BL32 memory region prevents the issue.
>
> The BL32 is typically common for the SoC family, so this change should
> probably go into the g12b.dtsi. Or probably even
> meson-g12-common.dtsi, which is where the BL31 reserved-memory is
> described.
Hi Kevin,
Would you be okay with the same change applied to GX devices too? - I
normally have these two catch-all patches in my tree to deal with random
tv box hardware and it would be great to drop them:
https://github.com/chewitt/linux/commit/4315ea4612389fc08d0a008b562cafbda96374fc
https://github.com/chewitt/linux/commit/3c0df794baa7ea9d32d8ad54530b5a056c770ea9
Christian
^ permalink raw reply
* RE: [PATCH v3 2/4] arm64: tegra: Add Tegra234 I2C devicetree nodes
From: Akhil R @ 2022-01-25 4:51 UTC (permalink / raw)
To: Dmitry Osipenko, devicetree@vger.kernel.org, Jonathan Hunter,
Laxman Dewangan, linux-i2c@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org,
Mikko Perttunen, robh+dt@kernel.org, thierry.reding@gmail.com
In-Reply-To: <c323b734-b134-2dc0-cfa2-c9f63f1c3ad8@gmail.com>
> 24.01.2022 14:18, Akhil R пишет:
> > Add device tree nodes for Tegra234 I2C controllers
> >
> > Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
> > ---
> > arch/arm64/boot/dts/nvidia/tegra234.dtsi | 121
> > +++++++++++++++++++++++++++++++
> > 1 file changed, 121 insertions(+)
> >
> > diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi
> > b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
> > index 6b6f1580..c686827 100644
> > --- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi
> > +++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
> > @@ -144,6 +144,96 @@
> > status = "disabled";
> > };
> >
> > + gen1_i2c: i2c@3160000 {
> > + compatible = "nvidia,tegra194-i2c";
> > + reg = <0x3160000 0x100>;
> > + status = "disabled";
> > + interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
> > + clock-frequency = <400000>;
> > + clocks = <&bpmp TEGRA234_CLK_I2C1
> > + &bpmp TEGRA234_CLK_PLLP_OUT0>;
> > + assigned-clocks = <&bpmp TEGRA234_CLK_I2C1>;
> > + assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLP_OUT0>;
> > + clock-names = "div-clk", "parent";
> > + resets = <&bpmp TEGRA234_RESET_I2C1>;
> > + reset-names = "i2c";
> > + };
>
> The patchset looks okay to me, thank you. I've one question:
>
> Could you please explain why the "PLLP" I2C timing configuration that is
> specified in the "example" section of Tegra TRM isn't suitable for T194/234?
> Why I2C Tegra kernel driver uses a different configuration?
The values in TRM are example settings. The values in driver are
more precise values based on characterization test results.
Regards,
Akhil
^ permalink raw reply
* Re: [PATCH V4 1/2] dt-bindings: pinctrl: Add binding for BCM4908 pinctrl
From: Linus Walleij @ 2022-01-25 0:42 UTC (permalink / raw)
To: Rafał Miłecki
Cc: Rob Herring, Álvaro Fernández Rojas, Jonas Gorski,
Randy Dunlap, Florian Fainelli, linux-gpio, devicetree,
bcm-kernel-feedback-list, Andy Shevchenko,
Rafał Miłecki, Rob Herring
In-Reply-To: <20220124102243.14912-1-zajec5@gmail.com>
On Mon, Jan 24, 2022 at 11:22 AM Rafał Miłecki <zajec5@gmail.com> wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
>
> It's hardware block that is part of every SoC from BCM4908 family.
>
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---
> V4: Rebased on top of the latest for-next which includes 5.17-rc1 now
Patch applied!
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH v9 2/2] clk: microchip: Add driver for Microchip PolarFire SoC
From: Stephen Boyd @ 2022-01-25 0:48 UTC (permalink / raw)
To: conor.dooley, devicetree, linux-clk, mturquette, robh+dt
Cc: krzysztof.kozlowski, geert, david.abdurachmanov, palmer,
daire.mcnamara, cyril.jean, conor.dooley, Padmarao Bengari
In-Reply-To: <20211216140022.16146-3-conor.dooley@microchip.com>
Quoting conor.dooley@microchip.com (2021-12-16 06:00:22)
> diff --git a/drivers/clk/microchip/Makefile b/drivers/clk/microchip/Makefile
> index f34b247e870f..0dce0b12eac4 100644
> --- a/drivers/clk/microchip/Makefile
> +++ b/drivers/clk/microchip/Makefile
> @@ -1,3 +1,5 @@
> # SPDX-License-Identifier: GPL-2.0-only
> -obj-$(CONFIG_COMMON_CLK_PIC32) += clk-core.o
Can you move this config to the microchip/Kconfig file?
> -obj-$(CONFIG_PIC32MZDA) += clk-pic32mzda.o
> +
> +obj-$(CONFIG_COMMON_CLK_PIC32) += clk-core.o
> +obj-$(CONFIG_PIC32MZDA) += clk-pic32mzda.o
Why did these two lines change? Please undo it.
> +obj-$(CONFIG_MCHP_CLK_MPFS) += clk-mpfs.o
> diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c
> new file mode 100644
> index 000000000000..f9bcfa864b67
> --- /dev/null
> +++ b/drivers/clk/microchip/clk-mpfs.c
> @@ -0,0 +1,439 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Daire McNamara,<daire.mcnamara@microchip.com>
> + * Copyright (C) 2020 Microchip Technology Inc. All rights reserved.
> + */
> +#include <linux/clk-provider.h>
> +#include <linux/clk.h>
Drop this include.
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <dt-bindings/clock/microchip,mpfs-clock.h>
> +
> +/* address offset of control registers */
> +#define REG_CLOCK_CONFIG_CR 0x08u
> +#define REG_SUBBLK_CLOCK_CR 0x84u
> +#define REG_SUBBLK_RESET_CR 0x88u
> +
> +struct mpfs_clock_data {
> + void __iomem *base;
> + struct clk_hw_onecell_data hw_data;
> +};
> +
> +struct mpfs_cfg_clock {
> + const char *name;
Why is this needed?
> + const struct clk_div_table *table;
> + struct clk_hw *parent;
Why is this needed?
> + unsigned long flags;
> + unsigned int id;
> + u8 shift;
> + u8 width;
> +};
> +
> +struct mpfs_cfg_hw_clock {
> + struct mpfs_cfg_clock cfg;
> + void __iomem *sys_base;
> + /* lock is used to prevent multiple writes */
> + spinlock_t *lock;
> + struct clk_hw hw;
> + struct clk_init_data init;
> +};
> +
> +#define to_mpfs_cfg_clk(_hw) container_of(_hw, struct mpfs_cfg_hw_clock, hw)
> +
> +struct mpfs_periph_clock {
> + const char *name;
> + struct clk_hw *parent;
Why are these two needed?
> + unsigned long flags;
> + unsigned int id;
> + u8 shift;
> +};
> +
> +struct mpfs_periph_hw_clock {
> + struct mpfs_periph_clock periph;
> + void __iomem *sys_base;
> + /* lock is used to prevent multiple writes */
> + spinlock_t *lock;
> + struct clk_hw hw;
> +};
> +
> +#define to_mpfs_periph_clk(_hw) container_of(_hw, struct mpfs_periph_hw_clock, hw)
> +
> +/*
> + * mpfs_clk_lock prevents anything else from writing to the
> + * mpfs clk block while a software locked register is being written.
> + */
> +static DEFINE_SPINLOCK(mpfs_clk_lock);
> +
> +static const struct clk_div_table mpfs_div_cpu_axi_table[] = {
> + { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
> + { 0, 0 }
> +};
> +
> +static const struct clk_div_table mpfs_div_ahb_table[] = {
> + { 1, 2 }, { 2, 4}, { 3, 8 },
> + { 0, 0 }
> +};
> +
> +static unsigned long mpfs_cfg_clk_recalc_rate(struct clk_hw *hw, unsigned long prate)
> +{
> + struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
> + struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
> + void __iomem *base_addr = cfg_hw->sys_base;
> + u32 val;
> +
> + val = readl_relaxed(base_addr + REG_CLOCK_CONFIG_CR) >> cfg->shift;
> + val &= clk_div_mask(cfg->width);
> +
> + return prate / (1u << val);
> +}
> +
> +static long mpfs_cfg_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate)
> +{
> + struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
> + struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
> +
> + return divider_round_rate(hw, rate, prate, cfg->table, cfg->width, cfg->flags);
> +}
> +
> +static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
> +{
> + struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
> + struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
> + void __iomem *base_addr = cfg_hw->sys_base;
> + unsigned long flags = 0;
> + u32 val;
> + int divider_setting;
> +
> + divider_setting = divider_get_val(rate, prate, cfg->table, cfg->width, cfg_hw->cfg.flags);
I think these are clk_hw flags and not divider flags being passed as the
last argument? If so, that's wrong.
> +
> + if (divider_setting < 0)
> + return divider_setting;
> +
> + spin_lock_irqsave(cfg_hw->lock, flags);
> +
> + val = readl_relaxed(base_addr + REG_CLOCK_CONFIG_CR);
> + val &= ~(clk_div_mask(cfg->width) << cfg_hw->cfg.shift);
> + val |= divider_setting << cfg->shift;
> + writel_relaxed(val, base_addr + REG_CLOCK_CONFIG_CR);
> +
> + spin_unlock_irqrestore(cfg_hw->lock, flags);
> +
> + return 0;
> +}
> +
> +static const struct clk_ops mpfs_clk_cfg_ops = {
> + .recalc_rate = mpfs_cfg_clk_recalc_rate,
> + .round_rate = mpfs_cfg_clk_round_rate,
> + .set_rate = mpfs_cfg_clk_set_rate,
> +};
> +
> +#define CLK_CFG(_id, _name, _shift, _width, _table, _flags) { \
> + .cfg.id = _id, \
> + .cfg.name = _name, \
> + .cfg.shift = _shift, \
> + .cfg.width = _width, \
> + .cfg.table = _table, \
> + }
> +
> +static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
> + CLK_CFG(CLK_CPU, "clk_cpu", 0, 2, mpfs_div_cpu_axi_table, 0),
> + CLK_CFG(CLK_AXI, "clk_axi", 2, 2, mpfs_div_cpu_axi_table, 0),
> + CLK_CFG(CLK_AHB, "clk_ahb", 4, 2, mpfs_div_ahb_table, 0),
> +};
> +
> +static struct clk_hw *mpfs_clk_register_cfg(struct device *dev,
> + struct mpfs_cfg_hw_clock *cfg_hw,
> + void __iomem *sys_base)
> +{
> + struct clk_hw *hw;
> + int err;
> +
> + cfg_hw->sys_base = sys_base;
> + cfg_hw->lock = &mpfs_clk_lock;
Instead of having a struct member why not use the lock directly as it's
all local to this file?
> +
> + hw = &cfg_hw->hw;
> + err = devm_clk_hw_register(dev, hw);
> + if (err)
> + return ERR_PTR(err);
> +
> + return hw;
> +}
> +
> +static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *cfg_hws,
> + unsigned int num_clks, struct mpfs_clock_data *data,
> + struct clk *clk_parent)
> +{
> + struct clk_hw *hw;
> + void __iomem *sys_base = data->base;
> + unsigned int i, id;
> +
> + for (i = 0; i < num_clks; i++) {
> + struct mpfs_cfg_hw_clock *cfg_hw = &cfg_hws[i];
> +
> + cfg_hw->cfg.parent = __clk_get_hw(clk_parent);
> + cfg_hw->hw.init = CLK_HW_INIT_HW(cfg_hw->cfg.name, cfg_hw->cfg.parent,
> + &mpfs_clk_cfg_ops, cfg_hw->cfg.flags);
> + hw = mpfs_clk_register_cfg(dev, cfg_hw, sys_base);
> + if (IS_ERR(hw)) {
> + dev_err(dev, "failed to register clock %s\n", cfg_hw->cfg.name);
> + goto err_clk;
> + }
> +
> + id = cfg_hws[i].cfg.id;
> + data->hw_data.hws[id] = hw;
> + }
> +
> + return 0;
> +
> +err_clk:
> + while (i--)
> + devm_clk_hw_unregister(dev, data->hw_data.hws[cfg_hws[i].cfg.id]);
The same comments below apply here.
> +
> + return PTR_ERR(hw);
> +}
> +
> +static int mpfs_periph_clk_enable(struct clk_hw *hw)
> +{
> + struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
> + struct mpfs_periph_clock *periph = &periph_hw->periph;
> + void __iomem *base_addr = periph_hw->sys_base;
> + u32 reg, val;
> + unsigned long flags = 0;
> +
> + spin_lock_irqsave(periph_hw->lock, flags);
> +
> + reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR);
> + val = reg & ~(1u << periph->shift);
> + writel_relaxed(val, base_addr + REG_SUBBLK_RESET_CR);
> +
> + reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR);
> + val = reg | (1u << periph->shift);
> + writel_relaxed(val, base_addr + REG_SUBBLK_CLOCK_CR);
> +
> + spin_unlock_irqrestore(periph_hw->lock, flags);
> +
> + return 0;
> +}
> +
> +static void mpfs_periph_clk_disable(struct clk_hw *hw)
> +{
> + struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
> + struct mpfs_periph_clock *periph = &periph_hw->periph;
> + void __iomem *base_addr = periph_hw->sys_base;
> + u32 reg, val;
> + unsigned long flags = 0;
Don't initialize flags for spin_lock_irqsave().
> +
> + spin_lock_irqsave(periph_hw->lock, flags);
> +
> + reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR);
> + val = reg | (1u << periph->shift);
> + writel_relaxed(val, base_addr + REG_SUBBLK_RESET_CR);
> +
> + reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR);
> + val = reg & ~(1u << periph->shift);
> + writel_relaxed(val, base_addr + REG_SUBBLK_CLOCK_CR);
> +
> + spin_unlock_irqrestore(periph_hw->lock, flags);
> +}
> +
> +static int mpfs_periph_clk_is_enabled(struct clk_hw *hw)
> +{
> + struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
> + struct mpfs_periph_clock *periph = &periph_hw->periph;
> + void __iomem *base_addr = periph_hw->sys_base;
> + u32 reg;
> +
> + reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR);
> + if ((reg & (1u << periph->shift)) == 0u) {
> + reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR);
> + if (reg & (1u << periph->shift))
> + return 1;
> + }
> +
> + return 0;
> +}
> +
> +static unsigned long mpfs_periph_clk_recalc_rate(struct clk_hw *hw, unsigned long prate)
> +{
> + return prate;
If it only returns the parent rate then this function can be omitted as
it's the default.
> +}
> +
> +static const struct clk_ops mpfs_periph_clk_ops = {
> + .enable = mpfs_periph_clk_enable,
> + .disable = mpfs_periph_clk_disable,
> + .is_enabled = mpfs_periph_clk_is_enabled,
> + .recalc_rate = mpfs_periph_clk_recalc_rate,
> +};
> +
> +#define CLK_PERIPH(_id, _name, _parent, _shift, _flags) { \
> + .periph.id = _id, \
Why the double tab?
> + .periph.name = _name, \
> + .periph.shift = _shift, \
> + .periph.flags = _flags, \
> + .periph.parent = _parent, \
> +}
> +
> +#define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT].hw)
> +
> +static struct mpfs_periph_hw_clock mpfs_periph_clks[] = {
> + CLK_PERIPH(CLK_ENVM, "clk_periph_envm", PARENT_CLK(AHB), 0, CLK_IS_CRITICAL),
All CLK_IS_CRITICAL needs a comment why it's critical.
> + CLK_PERIPH(CLK_MAC0, "clk_periph_mac0", PARENT_CLK(AHB), 1, 0),
> + CLK_PERIPH(CLK_MAC1, "clk_periph_mac1", PARENT_CLK(AHB), 2, 0),
> + CLK_PERIPH(CLK_MMC, "clk_periph_mmc", PARENT_CLK(AHB), 3, 0),
> + CLK_PERIPH(CLK_TIMER, "clk_periph_timer", PARENT_CLK(AHB), 4, 0),
> + CLK_PERIPH(CLK_MMUART0, "clk_periph_mmuart0", PARENT_CLK(AHB), 5, CLK_IS_CRITICAL),
> + CLK_PERIPH(CLK_MMUART1, "clk_periph_mmuart1", PARENT_CLK(AHB), 6, 0),
> + CLK_PERIPH(CLK_MMUART2, "clk_periph_mmuart2", PARENT_CLK(AHB), 7, 0),
> + CLK_PERIPH(CLK_MMUART3, "clk_periph_mmuart3", PARENT_CLK(AHB), 8, 0),
> + CLK_PERIPH(CLK_MMUART4, "clk_periph_mmuart4", PARENT_CLK(AHB), 9, 0),
> + CLK_PERIPH(CLK_SPI0, "clk_periph_spi0", PARENT_CLK(AHB), 10, 0),
> + CLK_PERIPH(CLK_SPI1, "clk_periph_spi1", PARENT_CLK(AHB), 11, 0),
> + CLK_PERIPH(CLK_I2C0, "clk_periph_i2c0", PARENT_CLK(AHB), 12, 0),
> + CLK_PERIPH(CLK_I2C1, "clk_periph_i2c1", PARENT_CLK(AHB), 13, 0),
> + CLK_PERIPH(CLK_CAN0, "clk_periph_can0", PARENT_CLK(AHB), 14, 0),
> + CLK_PERIPH(CLK_CAN1, "clk_periph_can1", PARENT_CLK(AHB), 15, 0),
> + CLK_PERIPH(CLK_USB, "clk_periph_usb", PARENT_CLK(AHB), 16, 0),
> + CLK_PERIPH(CLK_RTC, "clk_periph_rtc", PARENT_CLK(AHB), 18, 0),
> + CLK_PERIPH(CLK_QSPI, "clk_periph_qspi", PARENT_CLK(AHB), 19, 0),
> + CLK_PERIPH(CLK_GPIO0, "clk_periph_gpio0", PARENT_CLK(AHB), 20, 0),
> + CLK_PERIPH(CLK_GPIO1, "clk_periph_gpio1", PARENT_CLK(AHB), 21, 0),
> + CLK_PERIPH(CLK_GPIO2, "clk_periph_gpio2", PARENT_CLK(AHB), 22, 0),
> + CLK_PERIPH(CLK_DDRC, "clk_periph_ddrc", PARENT_CLK(AHB), 23, CLK_IS_CRITICAL),
> + CLK_PERIPH(CLK_FIC0, "clk_periph_fic0", PARENT_CLK(AHB), 24, CLK_IS_CRITICAL),
> + CLK_PERIPH(CLK_FIC1, "clk_periph_fic1", PARENT_CLK(AHB), 25, CLK_IS_CRITICAL),
> + CLK_PERIPH(CLK_FIC2, "clk_periph_fic2", PARENT_CLK(AHB), 26, CLK_IS_CRITICAL),
> + CLK_PERIPH(CLK_FIC3, "clk_periph_fic3", PARENT_CLK(AHB), 27, CLK_IS_CRITICAL),
> + CLK_PERIPH(CLK_ATHENA, "clk_periph_athena", PARENT_CLK(AHB), 28, 0),
> + CLK_PERIPH(CLK_CFM, "clk_periph_cfm", PARENT_CLK(AHB), 29, 0),
> +};
> +
> +static struct clk_hw *mpfs_clk_register_periph(struct device *dev,
Just return an int.
> + struct mpfs_periph_hw_clock *periph_hw,
> + void __iomem *sys_base)
> +{
> + struct clk_hw *hw;
> + int err;
> +
> + periph_hw->sys_base = sys_base;
> + periph_hw->lock = &mpfs_clk_lock;
> + hw = &periph_hw->hw;
> + err = devm_clk_hw_register(dev, hw);
> + if (err)
> + return ERR_PTR(err);
> +
> + return hw;
return devm_clk_hw_register(dev, &periph_hw->hw);
> +}
> +
> +static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_clock *periph_hws,
> + int num_clks, struct mpfs_clock_data *data)
> +{
> + struct clk_hw *hw;
> + void __iomem *sys_base = data->base;
> + unsigned int i, id;
> +
> + for (i = 0; i < num_clks; i++) {
> + struct mpfs_periph_hw_clock *periph_hw = &periph_hws[i];
> +
> + periph_hw->hw.init = CLK_HW_INIT_HW(periph_hw->periph.name,
> + periph_hw->periph.parent,
> + &mpfs_periph_clk_ops,
> + periph_hw->periph.flags);
> + hw = mpfs_clk_register_periph(dev, periph_hw, sys_base);
> + if (IS_ERR(hw)) {
I'd prefer this check for an int instead.
if (ret) {
dev_err_probe(dev, ....)
return ret;
> + dev_err(dev, "failed to register clock %s\n", periph_hw->periph.name);
> + goto err_clk;
> + }
> +
> + id = periph_hws[i].periph.id;
> + data->hw_data.hws[id] = hw;
And then this can use &periph_hw->hw directly.
> + }
> +
> + return 0;
> +
> +err_clk:
> + while (i--)
> + devm_clk_hw_unregister(dev, data->hw_data.hws[periph_hws[i].periph.id]);
There's no need for this. Let the clk_hws get unregistered when driver
probe fails.
> +
> + return PTR_ERR(hw);
> +}
> +
> +static int mpfs_clk_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct mpfs_clock_data *clk_data;
> + struct clk *clk_parent;
> + struct resource *res;
> + unsigned int num_clks;
> + int ret;
> +
> + //CLK_RESERVED is not part of cfg_clks nor periph_clks, so add 1
Use /* these style of comments */
> + num_clks = ARRAY_SIZE(mpfs_cfg_clks) + ARRAY_SIZE(mpfs_periph_clks) + 1;
> +
> + clk_data = devm_kzalloc(dev, struct_size(clk_data, hw_data.hws, num_clks), GFP_KERNEL);
> + if (!clk_data)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + clk_data->base = devm_ioremap_resource(dev, res);
devm_platform_ioremap_resource()
> + if (IS_ERR(clk_data->base))
> + return PTR_ERR(clk_data->base);
> +
> + clk_data->hw_data.num = num_clks;
> +
> + clk_parent = devm_clk_get(dev, NULL);
Use clk_parent_data instead please.
> + if (IS_ERR(clk_parent))
> + return PTR_ERR(clk_parent);
> +
> + ret = mpfs_clk_register_cfgs(dev, mpfs_cfg_clks, ARRAY_SIZE(mpfs_cfg_clks), clk_data,
> + clk_parent);
> + if (ret)
> + goto err_clk;
> +
> + ret = mpfs_clk_register_periphs(dev, mpfs_periph_clks, ARRAY_SIZE(mpfs_periph_clks),
> + clk_data);
> + if (ret)
> + goto err_clk;
> +
> + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, &clk_data->hw_data);
> + if (ret)
> + goto err_clk;
> +
> + dev_info(dev, "registered MPFS core clocks\n");
Make dev_dbg() or remove. We have driver core debug prints that
duplicate this.
> + return ret;
> +
> +err_clk:
> + dev_err(dev, "failed to register MPFS core clocks\n");
> + return ret;
Drop this goto zone please. The driver failing to probe message should
be pushed down into the respective functions instead of being generic
for the entire driver. Then the goto can be replaced with a simple
'return ret'.
> +}
> +
> +static const struct of_device_id mpfs_clk_of_match_table[] = {
> + { .compatible = "microchip,mpfs-clkcfg", },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, mpfs_clk_match_table);
> +
> +static struct platform_driver mpfs_clk_driver = {
> + .probe = mpfs_clk_probe,
> + .driver = {
> + .name = "microchip-mpfs-clkcfg",
> + .of_match_table = mpfs_clk_of_match_table,
> + },
> +};
> +
> +static int __init clk_mpfs_init(void)
> +{
> + return platform_driver_register(&mpfs_clk_driver);
> +}
> +core_initcall(clk_mpfs_init);
> +
> +static void __exit clk_mpfs_exit(void)
> +{
> + platform_driver_unregister(&mpfs_clk_driver);
> +}
> +module_exit(clk_mpfs_exit);
> +
> +MODULE_DESCRIPTION("Microchip PolarFire SoC Clock Driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:clk-mpfs");
An alias isn't required, please remove.
^ permalink raw reply
* [PATCH v3 2/3] spi: s3c64xx: Add spi port configuration for Tesla FSD SoC
From: Alim Akhtar @ 2022-01-25 3:16 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: devicetree, linus.walleij, robh+dt, krzysztof.kozlowski,
linux-samsung-soc, pankaj.dubey, broonie, andi, linux-spi,
Alim Akhtar, linux-fsd, Aswani Reddy
In-Reply-To: <20220125031604.76009-1-alim.akhtar@samsung.com>
Add compatible and port configuration for spi controller
for Tesla Full Self-Driving SoC.
Cc: linux-fsd@tesla.com
Signed-off-by: Aswani Reddy <aswani.reddy@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Reviewed-by: Andi Shyti <andi@etezian.org>
---
drivers/spi/spi-s3c64xx.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 386550fca81c..423518bf0270 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -1440,6 +1440,16 @@ static const struct s3c64xx_spi_port_config exynos5433_spi_port_config = {
.quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
};
+static struct s3c64xx_spi_port_config fsd_spi_port_config = {
+ .fifo_lvl_mask = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f},
+ .rx_lvl_offset = 15,
+ .tx_st_done = 25,
+ .high_speed = true,
+ .clk_from_cmu = true,
+ .clk_ioclk = false,
+ .quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
+};
+
static const struct platform_device_id s3c64xx_spi_driver_ids[] = {
{
.name = "s3c2443-spi",
@@ -1470,6 +1480,9 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = {
{ .compatible = "samsung,exynos5433-spi",
.data = (void *)&exynos5433_spi_port_config,
},
+ { .compatible = "tesla,fsd-spi",
+ .data = (void *)&fsd_spi_port_config,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);
--
2.25.1
^ permalink raw reply related
* [PATCH v3 3/3] arm64: dts: fsd: Add SPI device nodes
From: Alim Akhtar @ 2022-01-25 3:16 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: devicetree, linus.walleij, robh+dt, krzysztof.kozlowski,
linux-samsung-soc, pankaj.dubey, broonie, andi, linux-spi,
Aswani Reddy, linux-fsd, Alim Akhtar
In-Reply-To: <20220125031604.76009-1-alim.akhtar@samsung.com>
From: Aswani Reddy <aswani.reddy@samsung.com>
Adds device tree node for SPI IPs
Cc: linux-fsd@tesla.com
Signed-off-by: Aswani Reddy <aswani.reddy@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Reviewed-by: Andi Shyti <andi@etezian.org>
---
arch/arm64/boot/dts/tesla/fsd.dtsi | 57 ++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/arch/arm64/boot/dts/tesla/fsd.dtsi b/arch/arm64/boot/dts/tesla/fsd.dtsi
index b7f05f78c601..da4acd68b976 100644
--- a/arch/arm64/boot/dts/tesla/fsd.dtsi
+++ b/arch/arm64/boot/dts/tesla/fsd.dtsi
@@ -29,6 +29,9 @@ aliases {
pinctrl0 = &pinctrl_fsys0;
pinctrl1 = &pinctrl_peric;
pinctrl2 = &pinctrl_pmu;
+ spi0 = &spi_0;
+ spi1 = &spi_1;
+ spi2 = &spi_2;
};
cpus {
@@ -668,6 +671,60 @@ pinctrl_fsys0: pinctrl@15020000 {
reg = <0x0 0x15020000 0x0 0x1000>;
interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
};
+
+ spi_0: spi@14140000 {
+ compatible = "tesla,fsd-spi";
+ reg = <0x0 0x14140000 0x0 0x100>;
+ interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&pdma1 4>, <&pdma1 5>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&clock_peric PERIC_PCLK_SPI0>,
+ <&clock_peric PERIC_SCLK_SPI0>;
+ clock-names = "spi", "spi_busclk0";
+ samsung,spi-src-clk = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_bus>;
+ num-cs = <1>;
+ status = "disabled";
+ };
+
+ spi_1: spi@14150000 {
+ compatible = "tesla,fsd-spi";
+ reg = <0x0 0x14150000 0x0 0x100>;
+ interrupts = <GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&pdma1 6>, <&pdma1 7>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&clock_peric PERIC_PCLK_SPI1>,
+ <&clock_peric PERIC_SCLK_SPI1>;
+ clock-names = "spi", "spi_busclk0";
+ samsung,spi-src-clk = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_bus>;
+ num-cs = <1>;
+ status = "disabled";
+ };
+
+ spi_2: spi@14160000 {
+ compatible = "tesla,fsd-spi";
+ reg = <0x0 0x14160000 0x0 0x100>;
+ interrupts = <GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&pdma1 8>, <&pdma1 9>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&clock_peric PERIC_PCLK_SPI2>,
+ <&clock_peric PERIC_SCLK_SPI2>;
+ clock-names = "spi", "spi_busclk0";
+ samsung,spi-src-clk = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi2_bus>;
+ num-cs = <1>;
+ status = "disabled";
+ };
};
};
--
2.25.1
^ permalink raw reply related
* [PATCH v3 0/3] Add FSD SPI support
From: Alim Akhtar @ 2022-01-25 3:16 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: devicetree, linus.walleij, robh+dt, krzysztof.kozlowski,
linux-samsung-soc, pankaj.dubey, broonie, andi, linux-spi,
Alim Akhtar
In-Reply-To: <CGME20220125032811epcas5p3ef7b2f4e4906c1da8ccb4a0b3ed9a591@epcas5p3.samsung.com>
Adds support for SPI controller found in Tesla FSD SoC
- Changes since v2
* Addressed review comments of Andi
* rebased on Krzysztof's v6 spi schema changes
* Added tags
-Changes since v1
* Splited SPI changes from a larger inital patch set
* Rebased on Krzysztof's latest (v5) SPI schema changes
* Added tag
Note: This series is depended on [1] patches which adds
support of FSD SoC and on Krzysztof's v6 [2] of spi schema changes
[1] https://lkml.org/lkml/2022/1/24/583
[2] https://lkml.org/lkml/2022/1/24/120
Alim Akhtar (2):
spi: dt-bindings: samsung: Add fsd spi compatible
spi: s3c64xx: Add spi port configuration for Tesla FSD SoC
Aswani Reddy (1):
arm64: dts: fsd: Add SPI device nodes
.../devicetree/bindings/spi/samsung,spi.yaml | 1 +
arch/arm64/boot/dts/tesla/fsd.dtsi | 57 +++++++++++++++++++
drivers/spi/spi-s3c64xx.c | 13 +++++
3 files changed, 71 insertions(+)
--
2.25.1
^ permalink raw reply
* [PATCH v3 1/3] spi: dt-bindings: samsung: Add fsd spi compatible
From: Alim Akhtar @ 2022-01-25 3:16 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: devicetree, linus.walleij, robh+dt, krzysztof.kozlowski,
linux-samsung-soc, pankaj.dubey, broonie, andi, linux-spi,
Alim Akhtar, linux-fsd, Adithya K V
In-Reply-To: <20220125031604.76009-1-alim.akhtar@samsung.com>
Adds spi controller dt-binding compatible information for
Tesla Full Self-Driving (FSD) SoC.
Cc: linux-fsd@tesla.com
Signed-off-by: Adithya K V <adithya.kv@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Reviewed-by: Andi Shyti <andi@etezian.org>
---
Documentation/devicetree/bindings/spi/samsung,spi.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/spi/samsung,spi.yaml b/Documentation/devicetree/bindings/spi/samsung,spi.yaml
index 61c77088e8ee..bf9a76d931d2 100644
--- a/Documentation/devicetree/bindings/spi/samsung,spi.yaml
+++ b/Documentation/devicetree/bindings/spi/samsung,spi.yaml
@@ -21,6 +21,7 @@ properties:
- samsung,s3c6410-spi
- samsung,s5pv210-spi # for S5PV210 and S5PC110
- samsung,exynos5433-spi
+ - tesla,fsd-spi
- const: samsung,exynos7-spi
deprecated: true
--
2.25.1
^ permalink raw reply related
* [PATCH 3/3] ARM: dts: qcom: basic HP TouchPad support
From: Ben Wolsieffer @ 2022-01-25 2:07 UTC (permalink / raw)
Cc: Ben Wolsieffer, Andy Gross, Bjorn Andersson, Rob Herring,
Arnd Bergmann, Olof Johansson, soc, Stephen Boyd, linux-arm-msm,
devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.1643075547.git.benwolsieffer@gmail.com>
Modify the Dragonboard device tree to support the most basic hardware on
the HP TouchPad. The headphone UART port and eMMC are supported.
Signed-off-by: Ben Wolsieffer <benwolsieffer@gmail.com>
---
arch/arm/boot/dts/qcom-apq8060-tenderloin.dts | 549 ++----------------
1 file changed, 45 insertions(+), 504 deletions(-)
diff --git a/arch/arm/boot/dts/qcom-apq8060-tenderloin.dts b/arch/arm/boot/dts/qcom-apq8060-tenderloin.dts
index 996e73aa0b0b..e294f3920b9f 100644
--- a/arch/arm/boot/dts/qcom-apq8060-tenderloin.dts
+++ b/arch/arm/boot/dts/qcom-apq8060-tenderloin.dts
@@ -14,6 +14,8 @@ aliases {
};
chosen {
+ /* Bootloader passes console=tty1, which overrides stdout-path */
+ bootargs = "console=ttyMSM0,115200 earlycon";
stdout-path = "serial0:115200n8";
};
@@ -30,67 +32,18 @@ vph: regulator-fixed {
regulator-always-on;
regulator-boot-on;
};
-
- /* GPIO controlled ethernet power regulator */
- dragon_veth: xc622a331mrg {
- compatible = "regulator-fixed";
- regulator-name = "XC6222A331MR-G";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- vin-supply = <&vph>;
- gpio = <&pm8058_gpio 40 GPIO_ACTIVE_HIGH>;
- enable-active-high;
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_veth_gpios>;
- regulator-always-on;
- };
-
- /* VDDvario fixed regulator */
- dragon_vario: nds332p {
- compatible = "regulator-fixed";
- regulator-name = "NDS332P";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- vin-supply = <&pm8058_s3>;
- };
-
- /* This is a levelshifter for SDCC5 */
- dragon_vio_txb: txb0104rgyr {
- compatible = "regulator-fixed";
- regulator-name = "Dragon SDCC levelshifter";
- vin-supply = <&pm8058_l14>;
- regulator-always-on;
- };
- };
-
- /*
- * Capella CM3605 light and proximity sensor mounted directly
- * on the sensor board.
- */
- cm3605 {
- compatible = "capella,cm3605";
- vdd-supply = <&pm8058_l14>; // 2.85V
- aset-gpios = <&pm8058_gpio 35 GPIO_ACTIVE_LOW>;
- capella,aset-resistance-ohms = <100000>;
- /* Trig on both edges - getting close or far away */
- interrupts-extended = <&pm8058_gpio 34 IRQ_TYPE_EDGE_BOTH>;
- /* MPP05 analog input to the XOADC */
- io-channels = <&xoadc 0x00 0x05>;
- io-channel-names = "aout";
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_cm3605_gpios>, <&dragon_cm3605_mpps>;
};
soc {
pinctrl@800000 {
- /* eMMMC pins, all 8 data lines connected */
- dragon_sdcc1_pins: sdcc1 {
+ /* eMMC pins, all 8 data lines connected */
+ emmc_pins: sdcc1 {
mux {
pins = "gpio159", "gpio160", "gpio161",
"gpio162", "gpio163", "gpio164",
"gpio165", "gpio166", "gpio167",
"gpio168";
- function = "sdc1";
+ function = "sdc1";
};
clk {
pins = "gpio167"; /* SDC1 CLK */
@@ -111,54 +64,7 @@ data {
};
};
- /*
- * The SDCC3 pins are hardcoded (non-muxable) but need some pin
- * configuration.
- */
- dragon_sdcc3_pins: sdcc3 {
- clk {
- pins = "sdc3_clk";
- drive-strength = <8>;
- bias-disable;
- };
- cmd {
- pins = "sdc3_cmd";
- drive-strength = <8>;
- bias-pull-up;
- };
- data {
- pins = "sdc3_data";
- drive-strength = <8>;
- bias-pull-up;
- };
- };
-
- /* Second SD card slot pins */
- dragon_sdcc5_pins: sdcc5 {
- mux {
- pins = "gpio95", "gpio96", "gpio97",
- "gpio98", "gpio99", "gpio100";
- function = "sdc5";
- };
- clk {
- pins = "gpio97"; /* SDC5 CLK */
- drive-strength = <16>;
- bias-disable;
- };
- cmd {
- pins = "gpio95"; /* SDC5 CMD */
- drive-strength = <10>;
- bias-pull-up;
- };
- data {
- /* SDC5 D0 to D3 */
- pins = "gpio96", "gpio98", "gpio99", "gpio100";
- drive-strength = <10>;
- bias-pull-up;
- };
- };
-
- dragon_gsbi8_i2c_pins: gsbi8_i2c {
+ gsbi8_i2c_pins: gsbi8_i2c {
mux {
pins = "gpio64", "gpio65";
function = "gsbi8";
@@ -171,205 +77,33 @@ pinconf {
};
};
- dragon_gsbi12_i2c_pins: gsbi12_i2c {
- mux {
- pins = "gpio115", "gpio116";
- function = "gsbi12";
- };
- pinconf {
- pins = "gpio115", "gpio116";
- drive-strength = <16>;
- /* These have external pull-up 4.7kOhm to 1.8V */
- bias-disable;
- };
- };
-
- /* Primary serial port uart 0 pins */
- dragon_gsbi12_serial_pins: gsbi12_serial {
+ /* Headphone UART pins */
+ headphone_uart_pins: gsbi12_serial {
mux {
pins = "gpio117", "gpio118";
function = "gsbi12";
};
- tx {
- pins = "gpio117";
- drive-strength = <8>;
- bias-disable;
- };
rx {
- pins = "gpio118";
+ pins = "gpio117";
drive-strength = <2>;
bias-pull-up;
};
- };
-
- dragon_ebi2_pins: ebi2 {
- /*
- * Pins used by EBI2 on the Dragonboard, actually only
- * CS2 is used by a real peripheral. CS0 is just
- * routed to a test point.
- */
- mux0 {
- pins =
- /* "gpio39", CS1A_N this is not good to mux */
- "gpio40", /* CS2A_N */
- "gpio134"; /* CS0_N testpoint TP29 */
- function = "ebi2cs";
- };
- mux1 {
- pins =
- /* EBI2_ADDR_7 downto EBI2_ADDR_0 address bus */
- "gpio123", "gpio124", "gpio125", "gpio126",
- "gpio127", "gpio128", "gpio129", "gpio130",
- /* EBI2_DATA_15 downto EBI2_DATA_0 data bus */
- "gpio135", "gpio136", "gpio137", "gpio138",
- "gpio139", "gpio140", "gpio141", "gpio142",
- "gpio143", "gpio144", "gpio145", "gpio146",
- "gpio147", "gpio148", "gpio149", "gpio150",
- "gpio151", /* EBI2_OE_N */
- "gpio153", /* EBI2_ADV */
- "gpio157"; /* EBI2_WE_N */
- function = "ebi2";
+ tx {
+ pins = "gpio118";
+ drive-strength = <8>;
+ bias-disable;
};
- };
-
- /* Interrupt line for the KXSD9 accelerometer */
- dragon_kxsd9_gpios: kxsd9 {
- irq {
- pins = "gpio57"; /* IRQ line */
- bias-pull-up;
+ /* Connect headphone jack to UART rather than audio */
+ enable {
+ pins = "gpio58";
+ function = "gpio";
+ output-high;
};
};
};
qcom,ssbi@500000 {
pmic@0 {
- keypad@148 {
- linux,keymap = <
- MATRIX_KEY(0, 0, KEY_MENU)
- MATRIX_KEY(0, 2, KEY_1)
- MATRIX_KEY(0, 3, KEY_4)
- MATRIX_KEY(0, 4, KEY_7)
- MATRIX_KEY(1, 0, KEY_UP)
- MATRIX_KEY(1, 1, KEY_LEFT)
- MATRIX_KEY(1, 2, KEY_DOWN)
- MATRIX_KEY(1, 3, KEY_5)
- MATRIX_KEY(1, 3, KEY_8)
- MATRIX_KEY(2, 0, KEY_HOME)
- MATRIX_KEY(2, 1, KEY_REPLY)
- MATRIX_KEY(2, 2, KEY_2)
- MATRIX_KEY(2, 3, KEY_6)
- MATRIX_KEY(3, 0, KEY_VOLUMEUP)
- MATRIX_KEY(3, 1, KEY_RIGHT)
- MATRIX_KEY(3, 2, KEY_3)
- MATRIX_KEY(3, 3, KEY_9)
- MATRIX_KEY(3, 4, KEY_SWITCHVIDEOMODE)
- MATRIX_KEY(4, 0, KEY_VOLUMEDOWN)
- MATRIX_KEY(4, 1, KEY_BACK)
- MATRIX_KEY(4, 2, KEY_CAMERA)
- MATRIX_KEY(4, 3, KEY_KBDILLUMTOGGLE)
- >;
- keypad,num-rows = <6>;
- keypad,num-columns = <5>;
- };
-
- gpio@150 {
- dragon_ethernet_gpios: ethernet-gpios {
- pinconf {
- pins = "gpio7";
- function = "normal";
- input-enable;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_bmp085_gpios: bmp085-gpios {
- pinconf {
- pins = "gpio16";
- function = "normal";
- input-enable;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_mpu3050_gpios: mpu3050-gpios {
- pinconf {
- pins = "gpio17";
- function = "normal";
- input-enable;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_sdcc3_gpios: sdcc3-gpios {
- pinconf {
- pins = "gpio22";
- function = "normal";
- input-enable;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_sdcc5_gpios: sdcc5-gpios {
- pinconf {
- pins = "gpio26";
- function = "normal";
- input-enable;
- bias-pull-up;
- qcom,pull-up-strength = <PMIC_GPIO_PULL_UP_30>;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_ak8975_gpios: ak8975-gpios {
- pinconf {
- pins = "gpio33";
- function = "normal";
- input-enable;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_cm3605_gpios: cm3605-gpios {
- /* Pin 34 connected to the proxy IRQ */
- pinconf_gpio34 {
- pins = "gpio34";
- function = "normal";
- input-enable;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- /* Pin 35 connected to ASET */
- pinconf_gpio35 {
- pins = "gpio35";
- function = "normal";
- output-high;
- bias-disable;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- dragon_veth_gpios: veth-gpios {
- pinconf {
- pins = "gpio40";
- function = "normal";
- bias-disable;
- drive-push-pull;
- };
- };
- };
-
- mpps@50 {
- dragon_cm3605_mpps: cm3605-mpps-state {
- pinconf {
- pins = "mpp5";
- function = "analog";
- input-enable;
- bias-high-impedance;
- /* Let's use channel 5 */
- qcom,amux-route = <PMIC_MPP_AMUX_ROUTE_CH5>;
- power-source = <PM8058_GPIO_S3>;
- };
- };
- };
-
xoadc@197 {
/* Reference voltage 2.2 V */
xoadc-ref-supply = <&pm8058_l18>;
@@ -396,46 +130,6 @@ mpp9@9 {
reg = <0x00 0x09>;
};
};
-
- led@48 {
- /*
- * The keypad LED @0x48 is routed to
- * the sensor board where it is
- * connected to an infrared LED
- * SFH4650 (60mW, @850nm) next to the
- * ambient light and proximity sensor
- * Capella Microsystems CM3605.
- */
- compatible = "qcom,pm8058-keypad-led";
- reg = <0x48>;
- label = "pm8058:infrared:proximitysensor";
- default-state = "off";
- linux,default-trigger = "cm3605";
- };
- led@131 {
- compatible = "qcom,pm8058-led";
- reg = <0x131>;
- label = "pm8058:red";
- default-state = "off";
- };
- led@132 {
- /*
- * This is actually green too on my
- * board, but documented as yellow.
- */
- compatible = "qcom,pm8058-led";
- reg = <0x132>;
- label = "pm8058:yellow";
- default-state = "off";
- linux,default-trigger = "mmc0";
- };
- led@133 {
- compatible = "qcom,pm8058-led";
- reg = <0x133>;
- label = "pm8058:green";
- default-state = "on";
- linux,default-trigger = "heartbeat";
- };
};
};
@@ -446,151 +140,18 @@ gsbi@19800000 {
i2c@19880000 {
status = "okay";
pinctrl-names = "default";
- pinctrl-0 = <&dragon_gsbi8_i2c_pins>;
-
- eeprom@52 {
- /* A 16KiB Platform ID EEPROM on the CPU carrier board */
- compatible = "atmel,24c128";
- reg = <0x52>;
- vcc-supply = <&pm8058_s3>;
- pagesize = <64>;
- };
- wm8903: wm8903@1a {
- /* This Woolfson Micro device has an unrouted interrupt line */
- compatible = "wlf,wm8903";
- reg = <0x1a>;
-
- AVDD-supply = <&pm8058_l16>;
- CPVDD-supply = <&pm8058_l16>;
- DBVDD-supply = <&pm8058_s3>;
- DCVDD-supply = <&pm8058_l0>;
-
- gpio-controller;
- #gpio-cells = <2>;
-
- micdet-cfg = <0>;
- micdet-delay = <100>;
- gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
- };
+ pinctrl-0 = <&gsbi8_i2c_pins>;
};
};
gsbi@19c00000 {
status = "okay";
- qcom,mode = <GSBI_PROT_I2C_UART>;
+ qcom,mode = <GSBI_PROT_UART_W_FC>;
serial@19c40000 {
status = "okay";
pinctrl-names = "default";
- pinctrl-0 = <&dragon_gsbi12_serial_pins>;
- };
-
- i2c@19c80000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_gsbi12_i2c_pins>;
-
- ak8975@c {
- compatible = "asahi-kasei,ak8975";
- reg = <0x0c>;
- interrupt-parent = <&pm8058_gpio>;
- interrupts = <33 IRQ_TYPE_EDGE_RISING>;
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_ak8975_gpios>;
- vid-supply = <&pm8058_lvs0>; // 1.8V
- vdd-supply = <&pm8058_l14>; // 2.85V
- };
- bmp085@77 {
- compatible = "bosch,bmp085";
- reg = <0x77>;
- interrupt-parent = <&pm8058_gpio>;
- interrupts = <16 IRQ_TYPE_EDGE_RISING>;
- reset-gpios = <&tlmm 86 GPIO_ACTIVE_LOW>;
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_bmp085_gpios>;
- vddd-supply = <&pm8058_lvs0>; // 1.8V
- vdda-supply = <&pm8058_l14>; // 2.85V
- };
- mpu3050@68 {
- compatible = "invensense,mpu3050";
- reg = <0x68>;
- /*
- * GPIO17 is pulled high by a 10k
- * resistor to VLOGIC so needs to be
- * active low/falling edge.
- */
- interrupts-extended = <&pm8058_gpio 17 IRQ_TYPE_EDGE_FALLING>;
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_mpu3050_gpios>;
- vlogic-supply = <&pm8058_lvs0>; // 1.8V
- vdd-supply = <&pm8058_l14>; // 2.85V
-
- /*
- * The MPU-3050 acts as a hub for the
- * accelerometer.
- */
- i2c-gate {
- #address-cells = <1>;
- #size-cells = <0>;
-
- kxsd9@18 {
- compatible = "kionix,kxsd9";
- reg = <0x18>;
- interrupt-parent = <&tlmm>;
- interrupts = <57 IRQ_TYPE_EDGE_FALLING>;
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_kxsd9_gpios>;
- iovdd-supply = <&pm8058_lvs0>; // 1.8V
- vdd-supply = <&pm8058_l14>; // 2.85V
- };
- };
- };
- };
- };
-
- external-bus@1a100000 {
- /* The EBI2 will instantiate first, then populate its children */
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_ebi2_pins>;
-
- /*
- * An on-board SMSC LAN9221 chip for "debug ethernet",
- * which is actually just an ordinary ethernet on the
- * EBI2. This has a 25MHz chrystal next to it, so no
- * clocking is needed.
- */
- ethernet@2,0 {
- compatible = "smsc,lan9221", "smsc,lan9115";
- reg = <2 0x0 0x100>;
- /*
- * The second interrupt is the PME interrupt
- * for network wakeup, connected to the TLMM.
- */
- interrupts-extended = <&pm8058_gpio 7 IRQ_TYPE_EDGE_FALLING>,
- <&tlmm 29 IRQ_TYPE_EDGE_RISING>;
- reset-gpios = <&tlmm 30 GPIO_ACTIVE_LOW>;
- vdd33a-supply = <&dragon_veth>;
- vddvario-supply = <&dragon_vario>;
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_ethernet_gpios>;
- phy-mode = "mii";
- reg-io-width = <2>;
- smsc,force-external-phy;
- smsc,irq-push-pull;
-
- /*
- * SLOW chipselect config
- * Delay 9 cycles (140ns@64MHz) between SMSC
- * LAN9221 Ethernet controller reads and writes
- * on CS2.
- */
- qcom,xmem-recovery-cycles = <0>;
- qcom,xmem-write-hold-cycles = <3>;
- qcom,xmem-write-delta-cycles = <31>;
- qcom,xmem-read-delta-cycles = <28>;
- qcom,xmem-write-wait-cycles = <9>;
- qcom,xmem-read-wait-cycles = <9>;
+ pinctrl-0 = <&headphone_uart_pins>;
};
};
@@ -758,13 +319,13 @@ l9 {
bias-pull-down;
};
l10 {
- regulator-min-microvolt = <2600000>;
- regulator-max-microvolt = <2600000>;
+ regulator-min-microvolt = <3050000>;
+ regulator-max-microvolt = <3050000>;
bias-pull-down;
};
l11 {
- regulator-min-microvolt = <1500000>;
- regulator-max-microvolt = <1500000>;
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
bias-pull-down;
};
l12 {
@@ -790,10 +351,13 @@ l16 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
bias-pull-down;
- regulator-always-on;
+ /*
+ * RPM driver can't handle always-on regulators that are
+ * supplied by regulators initialized after them.
+ */
+ // regulator-always-on;
};
l17 {
- // 1.5V according to schematic
regulator-min-microvolt = <2600000>;
regulator-max-microvolt = <2600000>;
bias-pull-down;
@@ -804,8 +368,8 @@ l18 {
bias-pull-down;
};
l19 {
- regulator-min-microvolt = <2500000>;
- regulator-max-microvolt = <2500000>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
bias-pull-down;
};
l20 {
@@ -814,14 +378,16 @@ l20 {
bias-pull-down;
};
l21 {
- // 1.1 V according to schematic
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
bias-pull-down;
- regulator-always-on;
+ /*
+ * RPM driver can't handle always-on regulators that are
+ * supplied by regulators initialized after them.
+ */
+ // regulator-always-on;
};
l22 {
- // 1.2 V according to schematic
regulator-min-microvolt = <1150000>;
regulator-max-microvolt = <1150000>;
bias-pull-down;
@@ -845,7 +411,7 @@ l25 {
};
s0 {
- // regulator-min-microvolt = <500000>;
+ // regulator-min-microvolt = <800000>;
// regulator-max-microvolt = <1325000>;
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1100000>;
@@ -853,8 +419,8 @@ s0 {
bias-pull-down;
};
s1 {
- // regulator-min-microvolt = <500000>;
- // regulator-max-microvolt = <1250000>;
+ // regulator-min-microvolt = <800000>;
+ // regulator-max-microvolt = <1325000>;
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1100000>;
qcom,switch-mode-frequency = <1600000>;
@@ -871,15 +437,15 @@ s3 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
qcom,switch-mode-frequency = <1600000>;
- regulator-always-on;
bias-pull-down;
+ regulator-always-on;
};
s4 {
regulator-min-microvolt = <2200000>;
regulator-max-microvolt = <2200000>;
qcom,switch-mode-frequency = <1600000>;
- regulator-always-on;
bias-pull-down;
+ regulator-always-on;
};
/* LVS0 and LVS1 are just switches */
@@ -897,41 +463,16 @@ ncp {
};
};
};
+
amba {
- /* Internal 3.69 GiB eMMC */
+ /* Internal 16/32 GiB eMMC */
mmc@12400000 {
status = "okay";
pinctrl-names = "default";
- pinctrl-0 = <&dragon_sdcc1_pins>;
+ pinctrl-0 = <&emmc_pins>;
vmmc-supply = <&pm8901_l5>;
vqmmc-supply = <&pm8901_lvs0>;
};
-
- /* External micro SD card, directly connected, pulled up to 2.85 V */
- mmc@12180000 {
- status = "okay";
- /* Enable SSBI GPIO 22 as input, use for card detect */
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_sdcc3_pins>, <&dragon_sdcc3_gpios>;
- cd-gpios = <&pm8058_gpio 22 GPIO_ACTIVE_LOW>;
- wp-gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>;
- vmmc-supply = <&pm8058_l14>;
- };
-
- /*
- * Second external micro SD card, using two TXB104RGYR levelshifters
- * to lift from 1.8 V to 2.85 V
- */
- mmc@12200000 {
- status = "okay";
- /* Enable SSBI GPIO 26 as input, use for card detect */
- pinctrl-names = "default";
- pinctrl-0 = <&dragon_sdcc5_pins>, <&dragon_sdcc5_gpios>;
- cd-gpios = <&pm8058_gpio 26 GPIO_ACTIVE_LOW>;
- wp-gpios = <&tlmm 106 GPIO_ACTIVE_HIGH>;
- vmmc-supply = <&pm8058_l14>;
- vqmmc-supply = <&dragon_vio_txb>;
- };
};
};
};
--
2.34.1
^ permalink raw reply related
* [PATCH 2/3] dt-bindings: arm: qcom: document HP TouchPad
From: Ben Wolsieffer @ 2022-01-25 2:07 UTC (permalink / raw)
Cc: Ben Wolsieffer, Andy Gross, Bjorn Andersson, Rob Herring,
Arnd Bergmann, Olof Johansson, soc, Stephen Boyd, linux-arm-msm,
devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.1643075547.git.benwolsieffer@gmail.com>
Add binding documentation for the HP TouchPad.
Signed-off-by: Ben Wolsieffer <benwolsieffer@gmail.com>
---
Documentation/devicetree/bindings/arm/qcom.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml
index 370aab274cd1..f7418a8a49fc 100644
--- a/Documentation/devicetree/bindings/arm/qcom.yaml
+++ b/Documentation/devicetree/bindings/arm/qcom.yaml
@@ -119,6 +119,7 @@ properties:
- items:
- enum:
- qcom,apq8060-dragonboard
+ - qcom,apq8060-tenderloin
- qcom,msm8660-surf
- const: qcom,msm8660
--
2.34.1
^ permalink raw reply related
* [PATCH 1/3] ARM: dts: qcom: add HP TouchPad (tenderloin)
From: Ben Wolsieffer @ 2022-01-25 2:07 UTC (permalink / raw)
Cc: Ben Wolsieffer, Andy Gross, Bjorn Andersson, Rob Herring,
Arnd Bergmann, Olof Johansson, soc, Stephen Boyd, linux-arm-msm,
devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <cover.1643075547.git.benwolsieffer@gmail.com>
The device tree is a copy of the Dragonboard, which uses the same SoC.
Therefore, it is not usuable in its current form. Instead, this patch
serves as a reference to make it easier to review the changes needed to
support the TouchPad.
Signed-off-by: Ben Wolsieffer <benwolsieffer@gmail.com>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/qcom-apq8060-tenderloin.dts | 937 ++++++++++++++++++
2 files changed, 938 insertions(+)
create mode 100644 arch/arm/boot/dts/qcom-apq8060-tenderloin.dts
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 235ad559acb2..ce04c8b8b577 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -969,6 +969,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \
qcom-apq8016-sbc.dtb \
qcom-apq8026-lg-lenok.dtb \
qcom-apq8060-dragonboard.dtb \
+ qcom-apq8060-tenderloin.dtb \
qcom-apq8064-cm-qs600.dtb \
qcom-apq8064-ifc6410.dtb \
qcom-apq8064-sony-xperia-yuga.dtb \
diff --git a/arch/arm/boot/dts/qcom-apq8060-tenderloin.dts b/arch/arm/boot/dts/qcom-apq8060-tenderloin.dts
new file mode 100644
index 000000000000..996e73aa0b0b
--- /dev/null
+++ b/arch/arm/boot/dts/qcom-apq8060-tenderloin.dts
@@ -0,0 +1,937 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-mpp.h>
+#include "qcom-msm8660.dtsi"
+
+/ {
+ model = "HP TouchPad";
+ compatible = "qcom,apq8060-tenderloin", "qcom,msm8660";
+
+ aliases {
+ serial0 = &gsbi12_serial;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ regulators {
+ compatible = "simple-bus";
+
+ /* Main power of the board: 3.7V */
+ vph: regulator-fixed {
+ compatible = "regulator-fixed";
+ regulator-min-microvolt = <3700000>;
+ regulator-max-microvolt = <3700000>;
+ regulator-name = "VPH";
+ regulator-type = "voltage";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ /* GPIO controlled ethernet power regulator */
+ dragon_veth: xc622a331mrg {
+ compatible = "regulator-fixed";
+ regulator-name = "XC6222A331MR-G";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vph>;
+ gpio = <&pm8058_gpio 40 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_veth_gpios>;
+ regulator-always-on;
+ };
+
+ /* VDDvario fixed regulator */
+ dragon_vario: nds332p {
+ compatible = "regulator-fixed";
+ regulator-name = "NDS332P";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&pm8058_s3>;
+ };
+
+ /* This is a levelshifter for SDCC5 */
+ dragon_vio_txb: txb0104rgyr {
+ compatible = "regulator-fixed";
+ regulator-name = "Dragon SDCC levelshifter";
+ vin-supply = <&pm8058_l14>;
+ regulator-always-on;
+ };
+ };
+
+ /*
+ * Capella CM3605 light and proximity sensor mounted directly
+ * on the sensor board.
+ */
+ cm3605 {
+ compatible = "capella,cm3605";
+ vdd-supply = <&pm8058_l14>; // 2.85V
+ aset-gpios = <&pm8058_gpio 35 GPIO_ACTIVE_LOW>;
+ capella,aset-resistance-ohms = <100000>;
+ /* Trig on both edges - getting close or far away */
+ interrupts-extended = <&pm8058_gpio 34 IRQ_TYPE_EDGE_BOTH>;
+ /* MPP05 analog input to the XOADC */
+ io-channels = <&xoadc 0x00 0x05>;
+ io-channel-names = "aout";
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_cm3605_gpios>, <&dragon_cm3605_mpps>;
+ };
+
+ soc {
+ pinctrl@800000 {
+ /* eMMMC pins, all 8 data lines connected */
+ dragon_sdcc1_pins: sdcc1 {
+ mux {
+ pins = "gpio159", "gpio160", "gpio161",
+ "gpio162", "gpio163", "gpio164",
+ "gpio165", "gpio166", "gpio167",
+ "gpio168";
+ function = "sdc1";
+ };
+ clk {
+ pins = "gpio167"; /* SDC1 CLK */
+ drive-strength = <16>;
+ bias-disable;
+ };
+ cmd {
+ pins = "gpio168"; /* SDC1 CMD */
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+ data {
+ /* SDC1 D0 to D7 */
+ pins = "gpio159", "gpio160", "gpio161", "gpio162",
+ "gpio163", "gpio164", "gpio165", "gpio166";
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+ };
+
+ /*
+ * The SDCC3 pins are hardcoded (non-muxable) but need some pin
+ * configuration.
+ */
+ dragon_sdcc3_pins: sdcc3 {
+ clk {
+ pins = "sdc3_clk";
+ drive-strength = <8>;
+ bias-disable;
+ };
+ cmd {
+ pins = "sdc3_cmd";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ data {
+ pins = "sdc3_data";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ };
+
+ /* Second SD card slot pins */
+ dragon_sdcc5_pins: sdcc5 {
+ mux {
+ pins = "gpio95", "gpio96", "gpio97",
+ "gpio98", "gpio99", "gpio100";
+ function = "sdc5";
+ };
+ clk {
+ pins = "gpio97"; /* SDC5 CLK */
+ drive-strength = <16>;
+ bias-disable;
+ };
+ cmd {
+ pins = "gpio95"; /* SDC5 CMD */
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+ data {
+ /* SDC5 D0 to D3 */
+ pins = "gpio96", "gpio98", "gpio99", "gpio100";
+ drive-strength = <10>;
+ bias-pull-up;
+ };
+ };
+
+ dragon_gsbi8_i2c_pins: gsbi8_i2c {
+ mux {
+ pins = "gpio64", "gpio65";
+ function = "gsbi8";
+ };
+ pinconf {
+ pins = "gpio64", "gpio65";
+ drive-strength = <16>;
+ /* These have external pull-up 2.2kOhm to 1.8V */
+ bias-disable;
+ };
+ };
+
+ dragon_gsbi12_i2c_pins: gsbi12_i2c {
+ mux {
+ pins = "gpio115", "gpio116";
+ function = "gsbi12";
+ };
+ pinconf {
+ pins = "gpio115", "gpio116";
+ drive-strength = <16>;
+ /* These have external pull-up 4.7kOhm to 1.8V */
+ bias-disable;
+ };
+ };
+
+ /* Primary serial port uart 0 pins */
+ dragon_gsbi12_serial_pins: gsbi12_serial {
+ mux {
+ pins = "gpio117", "gpio118";
+ function = "gsbi12";
+ };
+ tx {
+ pins = "gpio117";
+ drive-strength = <8>;
+ bias-disable;
+ };
+ rx {
+ pins = "gpio118";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ dragon_ebi2_pins: ebi2 {
+ /*
+ * Pins used by EBI2 on the Dragonboard, actually only
+ * CS2 is used by a real peripheral. CS0 is just
+ * routed to a test point.
+ */
+ mux0 {
+ pins =
+ /* "gpio39", CS1A_N this is not good to mux */
+ "gpio40", /* CS2A_N */
+ "gpio134"; /* CS0_N testpoint TP29 */
+ function = "ebi2cs";
+ };
+ mux1 {
+ pins =
+ /* EBI2_ADDR_7 downto EBI2_ADDR_0 address bus */
+ "gpio123", "gpio124", "gpio125", "gpio126",
+ "gpio127", "gpio128", "gpio129", "gpio130",
+ /* EBI2_DATA_15 downto EBI2_DATA_0 data bus */
+ "gpio135", "gpio136", "gpio137", "gpio138",
+ "gpio139", "gpio140", "gpio141", "gpio142",
+ "gpio143", "gpio144", "gpio145", "gpio146",
+ "gpio147", "gpio148", "gpio149", "gpio150",
+ "gpio151", /* EBI2_OE_N */
+ "gpio153", /* EBI2_ADV */
+ "gpio157"; /* EBI2_WE_N */
+ function = "ebi2";
+ };
+ };
+
+ /* Interrupt line for the KXSD9 accelerometer */
+ dragon_kxsd9_gpios: kxsd9 {
+ irq {
+ pins = "gpio57"; /* IRQ line */
+ bias-pull-up;
+ };
+ };
+ };
+
+ qcom,ssbi@500000 {
+ pmic@0 {
+ keypad@148 {
+ linux,keymap = <
+ MATRIX_KEY(0, 0, KEY_MENU)
+ MATRIX_KEY(0, 2, KEY_1)
+ MATRIX_KEY(0, 3, KEY_4)
+ MATRIX_KEY(0, 4, KEY_7)
+ MATRIX_KEY(1, 0, KEY_UP)
+ MATRIX_KEY(1, 1, KEY_LEFT)
+ MATRIX_KEY(1, 2, KEY_DOWN)
+ MATRIX_KEY(1, 3, KEY_5)
+ MATRIX_KEY(1, 3, KEY_8)
+ MATRIX_KEY(2, 0, KEY_HOME)
+ MATRIX_KEY(2, 1, KEY_REPLY)
+ MATRIX_KEY(2, 2, KEY_2)
+ MATRIX_KEY(2, 3, KEY_6)
+ MATRIX_KEY(3, 0, KEY_VOLUMEUP)
+ MATRIX_KEY(3, 1, KEY_RIGHT)
+ MATRIX_KEY(3, 2, KEY_3)
+ MATRIX_KEY(3, 3, KEY_9)
+ MATRIX_KEY(3, 4, KEY_SWITCHVIDEOMODE)
+ MATRIX_KEY(4, 0, KEY_VOLUMEDOWN)
+ MATRIX_KEY(4, 1, KEY_BACK)
+ MATRIX_KEY(4, 2, KEY_CAMERA)
+ MATRIX_KEY(4, 3, KEY_KBDILLUMTOGGLE)
+ >;
+ keypad,num-rows = <6>;
+ keypad,num-columns = <5>;
+ };
+
+ gpio@150 {
+ dragon_ethernet_gpios: ethernet-gpios {
+ pinconf {
+ pins = "gpio7";
+ function = "normal";
+ input-enable;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_bmp085_gpios: bmp085-gpios {
+ pinconf {
+ pins = "gpio16";
+ function = "normal";
+ input-enable;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_mpu3050_gpios: mpu3050-gpios {
+ pinconf {
+ pins = "gpio17";
+ function = "normal";
+ input-enable;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_sdcc3_gpios: sdcc3-gpios {
+ pinconf {
+ pins = "gpio22";
+ function = "normal";
+ input-enable;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_sdcc5_gpios: sdcc5-gpios {
+ pinconf {
+ pins = "gpio26";
+ function = "normal";
+ input-enable;
+ bias-pull-up;
+ qcom,pull-up-strength = <PMIC_GPIO_PULL_UP_30>;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_ak8975_gpios: ak8975-gpios {
+ pinconf {
+ pins = "gpio33";
+ function = "normal";
+ input-enable;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_cm3605_gpios: cm3605-gpios {
+ /* Pin 34 connected to the proxy IRQ */
+ pinconf_gpio34 {
+ pins = "gpio34";
+ function = "normal";
+ input-enable;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ /* Pin 35 connected to ASET */
+ pinconf_gpio35 {
+ pins = "gpio35";
+ function = "normal";
+ output-high;
+ bias-disable;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ dragon_veth_gpios: veth-gpios {
+ pinconf {
+ pins = "gpio40";
+ function = "normal";
+ bias-disable;
+ drive-push-pull;
+ };
+ };
+ };
+
+ mpps@50 {
+ dragon_cm3605_mpps: cm3605-mpps-state {
+ pinconf {
+ pins = "mpp5";
+ function = "analog";
+ input-enable;
+ bias-high-impedance;
+ /* Let's use channel 5 */
+ qcom,amux-route = <PMIC_MPP_AMUX_ROUTE_CH5>;
+ power-source = <PM8058_GPIO_S3>;
+ };
+ };
+ };
+
+ xoadc@197 {
+ /* Reference voltage 2.2 V */
+ xoadc-ref-supply = <&pm8058_l18>;
+
+ /* Board-specific channels */
+ mpp5@5 {
+ /* Connected to AOUT of ALS sensor */
+ reg = <0x00 0x05>;
+ };
+ mpp6@6 {
+ /* Connected to test point TP43 */
+ reg = <0x00 0x06>;
+ };
+ mpp7@7 {
+ /* Connected to battery thermistor */
+ reg = <0x00 0x07>;
+ };
+ mpp8@8 {
+ /* Connected to battery ID detector */
+ reg = <0x00 0x08>;
+ };
+ mpp9@9 {
+ /* Connected to XO thermistor */
+ reg = <0x00 0x09>;
+ };
+ };
+
+ led@48 {
+ /*
+ * The keypad LED @0x48 is routed to
+ * the sensor board where it is
+ * connected to an infrared LED
+ * SFH4650 (60mW, @850nm) next to the
+ * ambient light and proximity sensor
+ * Capella Microsystems CM3605.
+ */
+ compatible = "qcom,pm8058-keypad-led";
+ reg = <0x48>;
+ label = "pm8058:infrared:proximitysensor";
+ default-state = "off";
+ linux,default-trigger = "cm3605";
+ };
+ led@131 {
+ compatible = "qcom,pm8058-led";
+ reg = <0x131>;
+ label = "pm8058:red";
+ default-state = "off";
+ };
+ led@132 {
+ /*
+ * This is actually green too on my
+ * board, but documented as yellow.
+ */
+ compatible = "qcom,pm8058-led";
+ reg = <0x132>;
+ label = "pm8058:yellow";
+ default-state = "off";
+ linux,default-trigger = "mmc0";
+ };
+ led@133 {
+ compatible = "qcom,pm8058-led";
+ reg = <0x133>;
+ label = "pm8058:green";
+ default-state = "on";
+ linux,default-trigger = "heartbeat";
+ };
+ };
+ };
+
+ gsbi@19800000 {
+ status = "okay";
+ qcom,mode = <GSBI_PROT_I2C>;
+
+ i2c@19880000 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_gsbi8_i2c_pins>;
+
+ eeprom@52 {
+ /* A 16KiB Platform ID EEPROM on the CPU carrier board */
+ compatible = "atmel,24c128";
+ reg = <0x52>;
+ vcc-supply = <&pm8058_s3>;
+ pagesize = <64>;
+ };
+ wm8903: wm8903@1a {
+ /* This Woolfson Micro device has an unrouted interrupt line */
+ compatible = "wlf,wm8903";
+ reg = <0x1a>;
+
+ AVDD-supply = <&pm8058_l16>;
+ CPVDD-supply = <&pm8058_l16>;
+ DBVDD-supply = <&pm8058_s3>;
+ DCVDD-supply = <&pm8058_l0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ micdet-cfg = <0>;
+ micdet-delay = <100>;
+ gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>;
+ };
+ };
+ };
+
+ gsbi@19c00000 {
+ status = "okay";
+ qcom,mode = <GSBI_PROT_I2C_UART>;
+
+ serial@19c40000 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_gsbi12_serial_pins>;
+ };
+
+ i2c@19c80000 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_gsbi12_i2c_pins>;
+
+ ak8975@c {
+ compatible = "asahi-kasei,ak8975";
+ reg = <0x0c>;
+ interrupt-parent = <&pm8058_gpio>;
+ interrupts = <33 IRQ_TYPE_EDGE_RISING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_ak8975_gpios>;
+ vid-supply = <&pm8058_lvs0>; // 1.8V
+ vdd-supply = <&pm8058_l14>; // 2.85V
+ };
+ bmp085@77 {
+ compatible = "bosch,bmp085";
+ reg = <0x77>;
+ interrupt-parent = <&pm8058_gpio>;
+ interrupts = <16 IRQ_TYPE_EDGE_RISING>;
+ reset-gpios = <&tlmm 86 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_bmp085_gpios>;
+ vddd-supply = <&pm8058_lvs0>; // 1.8V
+ vdda-supply = <&pm8058_l14>; // 2.85V
+ };
+ mpu3050@68 {
+ compatible = "invensense,mpu3050";
+ reg = <0x68>;
+ /*
+ * GPIO17 is pulled high by a 10k
+ * resistor to VLOGIC so needs to be
+ * active low/falling edge.
+ */
+ interrupts-extended = <&pm8058_gpio 17 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_mpu3050_gpios>;
+ vlogic-supply = <&pm8058_lvs0>; // 1.8V
+ vdd-supply = <&pm8058_l14>; // 2.85V
+
+ /*
+ * The MPU-3050 acts as a hub for the
+ * accelerometer.
+ */
+ i2c-gate {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ kxsd9@18 {
+ compatible = "kionix,kxsd9";
+ reg = <0x18>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <57 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_kxsd9_gpios>;
+ iovdd-supply = <&pm8058_lvs0>; // 1.8V
+ vdd-supply = <&pm8058_l14>; // 2.85V
+ };
+ };
+ };
+ };
+ };
+
+ external-bus@1a100000 {
+ /* The EBI2 will instantiate first, then populate its children */
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_ebi2_pins>;
+
+ /*
+ * An on-board SMSC LAN9221 chip for "debug ethernet",
+ * which is actually just an ordinary ethernet on the
+ * EBI2. This has a 25MHz chrystal next to it, so no
+ * clocking is needed.
+ */
+ ethernet@2,0 {
+ compatible = "smsc,lan9221", "smsc,lan9115";
+ reg = <2 0x0 0x100>;
+ /*
+ * The second interrupt is the PME interrupt
+ * for network wakeup, connected to the TLMM.
+ */
+ interrupts-extended = <&pm8058_gpio 7 IRQ_TYPE_EDGE_FALLING>,
+ <&tlmm 29 IRQ_TYPE_EDGE_RISING>;
+ reset-gpios = <&tlmm 30 GPIO_ACTIVE_LOW>;
+ vdd33a-supply = <&dragon_veth>;
+ vddvario-supply = <&dragon_vario>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_ethernet_gpios>;
+ phy-mode = "mii";
+ reg-io-width = <2>;
+ smsc,force-external-phy;
+ smsc,irq-push-pull;
+
+ /*
+ * SLOW chipselect config
+ * Delay 9 cycles (140ns@64MHz) between SMSC
+ * LAN9221 Ethernet controller reads and writes
+ * on CS2.
+ */
+ qcom,xmem-recovery-cycles = <0>;
+ qcom,xmem-write-hold-cycles = <3>;
+ qcom,xmem-write-delta-cycles = <31>;
+ qcom,xmem-read-delta-cycles = <28>;
+ qcom,xmem-write-wait-cycles = <9>;
+ qcom,xmem-read-wait-cycles = <9>;
+ };
+ };
+
+ rpm@104000 {
+ /*
+ * Set up of the PMIC RPM regulators for this board
+ * PM8901 supplies "preliminary regulators" whatever
+ * that means
+ */
+ pm8901-regulators {
+ vdd_l0-supply = <&pm8901_s4>;
+ vdd_l1-supply = <&vph>;
+ vdd_l2-supply = <&vph>;
+ vdd_l3-supply = <&vph>;
+ vdd_l4-supply = <&vph>;
+ vdd_l5-supply = <&vph>;
+ vdd_l6-supply = <&vph>;
+ /* vdd_s0-supply, vdd_s1-supply: SAW regulators */
+ vdd_s2-supply = <&vph>;
+ vdd_s3-supply = <&vph>;
+ vdd_s4-supply = <&vph>;
+ lvs0_in-supply = <&pm8058_s3>;
+ lvs1_in-supply = <&pm8901_s4>;
+ lvs2_in-supply = <&pm8058_l0>;
+ lvs3_in-supply = <&pm8058_s2>;
+ mvs_in-supply = <&pm8058_s3>;
+
+ l0 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+ l1 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ bias-pull-down;
+ };
+ l2 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <3300000>;
+ bias-pull-down;
+ };
+ l3 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ bias-pull-down;
+ };
+ l4 {
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <2600000>;
+ bias-pull-down;
+ };
+ l5 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ bias-pull-down;
+ };
+ l6 {
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ bias-pull-down;
+ };
+
+ /* s0 and s1 are SAW regulators controlled over SPM */
+ s2 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+ s3 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+ s4 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+
+ /* LVS0 thru 3 and mvs0 are just switches */
+ lvs0 {
+ regulator-always-on;
+ };
+ lvs1 { };
+ lvs2 { };
+ lvs3 { };
+ mvs0 {};
+
+ };
+
+ pm8058-regulators {
+ vdd_l0_l1_lvs-supply = <&pm8058_s3>;
+ vdd_l2_l11_l12-supply = <&vph>;
+ vdd_l3_l4_l5-supply = <&vph>;
+ vdd_l6_l7-supply = <&vph>;
+ vdd_l8-supply = <&vph>;
+ vdd_l9-supply = <&vph>;
+ vdd_l10-supply = <&vph>;
+ vdd_l13_l16-supply = <&pm8058_s4>;
+ vdd_l14_l15-supply = <&vph>;
+ vdd_l17_l18-supply = <&vph>;
+ vdd_l19_l20-supply = <&vph>;
+ vdd_l21-supply = <&pm8058_s3>;
+ vdd_l22-supply = <&pm8058_s3>;
+ vdd_l23_l24_l25-supply = <&pm8058_s3>;
+ vdd_s0-supply = <&vph>;
+ vdd_s1-supply = <&vph>;
+ vdd_s2-supply = <&vph>;
+ vdd_s3-supply = <&vph>;
+ vdd_s4-supply = <&vph>;
+ vdd_ncp-supply = <&vph>;
+
+ l0 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+ l1 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+ l2 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2600000>;
+ bias-pull-down;
+ };
+ l3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+ l4 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ bias-pull-down;
+ };
+ l5 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ bias-pull-down;
+ };
+ l6 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3600000>;
+ bias-pull-down;
+ };
+ l7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+ l8 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <3050000>;
+ bias-pull-down;
+ };
+ l9 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+ l10 {
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <2600000>;
+ bias-pull-down;
+ };
+ l11 {
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ bias-pull-down;
+ };
+ l12 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ bias-pull-down;
+ };
+ l13 {
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ bias-pull-down;
+ };
+ l14 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
+ l15 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ bias-pull-down;
+ };
+ l16 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ regulator-always-on;
+ };
+ l17 {
+ // 1.5V according to schematic
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <2600000>;
+ bias-pull-down;
+ };
+ l18 {
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ bias-pull-down;
+ };
+ l19 {
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ bias-pull-down;
+ };
+ l20 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+ l21 {
+ // 1.1 V according to schematic
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ regulator-always-on;
+ };
+ l22 {
+ // 1.2 V according to schematic
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ bias-pull-down;
+ };
+ l23 {
+ // Unused
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+ l24 {
+ // Unused
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+ l25 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ bias-pull-down;
+ };
+
+ s0 {
+ // regulator-min-microvolt = <500000>;
+ // regulator-max-microvolt = <1325000>;
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+ s1 {
+ // regulator-min-microvolt = <500000>;
+ // regulator-max-microvolt = <1250000>;
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+ s2 {
+ // 1.3 V according to schematic
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1400000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ };
+ s3 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <1600000>;
+ regulator-always-on;
+ bias-pull-down;
+ };
+ s4 {
+ regulator-min-microvolt = <2200000>;
+ regulator-max-microvolt = <2200000>;
+ qcom,switch-mode-frequency = <1600000>;
+ regulator-always-on;
+ bias-pull-down;
+ };
+
+ /* LVS0 and LVS1 are just switches */
+ lvs0 {
+ bias-pull-down;
+ };
+ lvs1 {
+ bias-pull-down;
+ };
+
+ ncp {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <1600000>;
+ };
+ };
+ };
+ amba {
+ /* Internal 3.69 GiB eMMC */
+ mmc@12400000 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_sdcc1_pins>;
+ vmmc-supply = <&pm8901_l5>;
+ vqmmc-supply = <&pm8901_lvs0>;
+ };
+
+ /* External micro SD card, directly connected, pulled up to 2.85 V */
+ mmc@12180000 {
+ status = "okay";
+ /* Enable SSBI GPIO 22 as input, use for card detect */
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_sdcc3_pins>, <&dragon_sdcc3_gpios>;
+ cd-gpios = <&pm8058_gpio 22 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>;
+ vmmc-supply = <&pm8058_l14>;
+ };
+
+ /*
+ * Second external micro SD card, using two TXB104RGYR levelshifters
+ * to lift from 1.8 V to 2.85 V
+ */
+ mmc@12200000 {
+ status = "okay";
+ /* Enable SSBI GPIO 26 as input, use for card detect */
+ pinctrl-names = "default";
+ pinctrl-0 = <&dragon_sdcc5_pins>, <&dragon_sdcc5_gpios>;
+ cd-gpios = <&pm8058_gpio 26 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&tlmm 106 GPIO_ACTIVE_HIGH>;
+ vmmc-supply = <&pm8058_l14>;
+ vqmmc-supply = <&dragon_vio_txb>;
+ };
+ };
+ };
+};
--
2.34.1
^ permalink raw reply related
* [PATCH v6 08/13] peci: Add support for PECI device drivers
From: Iwona Winiarska @ 2022-01-25 1:10 UTC (permalink / raw)
To: linux-kernel, openbmc, Greg Kroah-Hartman
Cc: devicetree, linux-aspeed, linux-arm-kernel, linux-hwmon,
linux-doc, Rob Herring, Joel Stanley, Andrew Jeffery,
Jean Delvare, Guenter Roeck, Arnd Bergmann, Olof Johansson,
Jonathan Corbet, Borislav Petkov, Pierre-Louis Bossart, Tony Luck,
Andy Shevchenko, Dan Williams, Randy Dunlap, Zev Weiss,
David Muller, Dave Hansen, Billy Tsai, Iwona Winiarska
In-Reply-To: <20220125011104.2480133-1-iwona.winiarska@intel.com>
Add support for PECI device drivers, which unlike PECI controller
drivers are actually able to provide functionalities to userspace.
Also, extend peci_request API to allow querying more details about PECI
device (e.g. model/family), that's going to be used to find a compatible
peci_driver.
Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
drivers/peci/core.c | 44 +++++++++
drivers/peci/device.c | 130 ++++++++++++++++++++++++
drivers/peci/internal.h | 74 ++++++++++++++
drivers/peci/request.c | 214 ++++++++++++++++++++++++++++++++++++++++
include/linux/peci.h | 19 ++++
5 files changed, 481 insertions(+)
diff --git a/drivers/peci/core.c b/drivers/peci/core.c
index e993615cf521..9c8cf07e51c7 100644
--- a/drivers/peci/core.c
+++ b/drivers/peci/core.c
@@ -160,8 +160,52 @@ struct peci_controller *devm_peci_controller_add(struct device *dev,
}
EXPORT_SYMBOL_NS_GPL(devm_peci_controller_add, PECI);
+static const struct peci_device_id *
+peci_bus_match_device_id(const struct peci_device_id *id, struct peci_device *device)
+{
+ while (id->family != 0) {
+ if (id->family == device->info.family &&
+ id->model == device->info.model)
+ return id;
+ id++;
+ }
+
+ return NULL;
+}
+
+static int peci_bus_device_match(struct device *dev, struct device_driver *drv)
+{
+ struct peci_device *device = to_peci_device(dev);
+ struct peci_driver *peci_drv = to_peci_driver(drv);
+
+ if (dev->type != &peci_device_type)
+ return 0;
+
+ return !!peci_bus_match_device_id(peci_drv->id_table, device);
+}
+
+static int peci_bus_device_probe(struct device *dev)
+{
+ struct peci_device *device = to_peci_device(dev);
+ struct peci_driver *driver = to_peci_driver(dev->driver);
+
+ return driver->probe(device, peci_bus_match_device_id(driver->id_table, device));
+}
+
+static void peci_bus_device_remove(struct device *dev)
+{
+ struct peci_device *device = to_peci_device(dev);
+ struct peci_driver *driver = to_peci_driver(dev->driver);
+
+ if (driver->remove)
+ driver->remove(device);
+}
+
struct bus_type peci_bus_type = {
.name = "peci",
+ .match = peci_bus_device_match,
+ .probe = peci_bus_device_probe,
+ .remove = peci_bus_device_remove,
.bus_groups = peci_bus_groups,
};
diff --git a/drivers/peci/device.c b/drivers/peci/device.c
index d10ed1cfcd48..184b5e650b0b 100644
--- a/drivers/peci/device.c
+++ b/drivers/peci/device.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2018-2021 Intel Corporation
+#include <linux/bitfield.h>
#include <linux/peci.h>
#include <linux/slab.h>
@@ -13,6 +14,104 @@
*/
static DEFINE_MUTEX(peci_device_del_lock);
+#define REVISION_NUM_MASK GENMASK(15, 8)
+static int peci_get_revision(struct peci_device *device, u8 *revision)
+{
+ struct peci_request *req;
+ u64 dib;
+
+ req = peci_xfer_get_dib(device);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ /*
+ * PECI device may be in a state where it is unable to return a proper
+ * DIB, in which case it returns 0 as DIB value.
+ * Let's treat this as an error to avoid carrying on with the detection
+ * using invalid revision.
+ */
+ dib = peci_request_dib_read(req);
+ if (dib == 0) {
+ peci_request_free(req);
+ return -EIO;
+ }
+
+ *revision = FIELD_GET(REVISION_NUM_MASK, dib);
+
+ peci_request_free(req);
+
+ return 0;
+}
+
+static int peci_get_cpu_id(struct peci_device *device, u32 *cpu_id)
+{
+ struct peci_request *req;
+ int ret;
+
+ req = peci_xfer_pkg_cfg_readl(device, PECI_PCS_PKG_ID, PECI_PKG_ID_CPU_ID);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+
+ ret = peci_request_status(req);
+ if (ret)
+ goto out_req_free;
+
+ *cpu_id = peci_request_data_readl(req);
+out_req_free:
+ peci_request_free(req);
+
+ return ret;
+}
+
+static unsigned int peci_x86_cpu_family(unsigned int sig)
+{
+ unsigned int x86;
+
+ x86 = (sig >> 8) & 0xf;
+
+ if (x86 == 0xf)
+ x86 += (sig >> 20) & 0xff;
+
+ return x86;
+}
+
+static unsigned int peci_x86_cpu_model(unsigned int sig)
+{
+ unsigned int fam, model;
+
+ fam = peci_x86_cpu_family(sig);
+
+ model = (sig >> 4) & 0xf;
+
+ if (fam >= 0x6)
+ model += ((sig >> 16) & 0xf) << 4;
+
+ return model;
+}
+
+static int peci_device_info_init(struct peci_device *device)
+{
+ u8 revision;
+ u32 cpu_id;
+ int ret;
+
+ ret = peci_get_cpu_id(device, &cpu_id);
+ if (ret)
+ return ret;
+
+ device->info.family = peci_x86_cpu_family(cpu_id);
+ device->info.model = peci_x86_cpu_model(cpu_id);
+
+ ret = peci_get_revision(device, &revision);
+ if (ret)
+ return ret;
+ device->info.peci_revision = revision;
+
+ device->info.socket_id = device->addr - PECI_BASE_ADDR;
+
+ return 0;
+}
+
static int peci_detect(struct peci_controller *controller, u8 addr)
{
/*
@@ -82,6 +181,10 @@ int peci_device_create(struct peci_controller *controller, u8 addr)
device->dev.bus = &peci_bus_type;
device->dev.type = &peci_device_type;
+ ret = peci_device_info_init(device);
+ if (ret)
+ goto err_put;
+
ret = dev_set_name(&device->dev, "%d-%02x", controller->id, device->addr);
if (ret)
goto err_put;
@@ -108,6 +211,33 @@ void peci_device_destroy(struct peci_device *device)
mutex_unlock(&peci_device_del_lock);
}
+int __peci_driver_register(struct peci_driver *driver, struct module *owner,
+ const char *mod_name)
+{
+ driver->driver.bus = &peci_bus_type;
+ driver->driver.owner = owner;
+ driver->driver.mod_name = mod_name;
+
+ if (!driver->probe) {
+ pr_err("peci: trying to register driver without probe callback\n");
+ return -EINVAL;
+ }
+
+ if (!driver->id_table) {
+ pr_err("peci: trying to register driver without device id table\n");
+ return -EINVAL;
+ }
+
+ return driver_register(&driver->driver);
+}
+EXPORT_SYMBOL_NS_GPL(__peci_driver_register, PECI);
+
+void peci_driver_unregister(struct peci_driver *driver)
+{
+ driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL_NS_GPL(peci_driver_unregister, PECI);
+
static void peci_device_release(struct device *dev)
{
struct peci_device *device = to_peci_device(dev);
diff --git a/drivers/peci/internal.h b/drivers/peci/internal.h
index 978e12c8e1d3..52c02e12874f 100644
--- a/drivers/peci/internal.h
+++ b/drivers/peci/internal.h
@@ -19,6 +19,35 @@ struct peci_request;
struct peci_request *peci_request_alloc(struct peci_device *device, u8 tx_len, u8 rx_len);
void peci_request_free(struct peci_request *req);
+int peci_request_status(struct peci_request *req);
+
+u64 peci_request_dib_read(struct peci_request *req);
+
+u8 peci_request_data_readb(struct peci_request *req);
+u16 peci_request_data_readw(struct peci_request *req);
+u32 peci_request_data_readl(struct peci_request *req);
+u64 peci_request_data_readq(struct peci_request *req);
+
+struct peci_request *peci_xfer_get_dib(struct peci_device *device);
+struct peci_request *peci_xfer_get_temp(struct peci_device *device);
+
+struct peci_request *peci_xfer_pkg_cfg_readb(struct peci_device *device, u8 index, u16 param);
+struct peci_request *peci_xfer_pkg_cfg_readw(struct peci_device *device, u8 index, u16 param);
+struct peci_request *peci_xfer_pkg_cfg_readl(struct peci_device *device, u8 index, u16 param);
+struct peci_request *peci_xfer_pkg_cfg_readq(struct peci_device *device, u8 index, u16 param);
+
+/**
+ * struct peci_device_id - PECI device data to match
+ * @data: pointer to driver private data specific to device
+ * @family: device family
+ * @model: device model
+ */
+struct peci_device_id {
+ const void *data;
+ u16 family;
+ u8 model;
+};
+
extern struct device_type peci_device_type;
extern const struct attribute_group *peci_device_groups[];
@@ -28,6 +57,51 @@ void peci_device_destroy(struct peci_device *device);
extern struct bus_type peci_bus_type;
extern const struct attribute_group *peci_bus_groups[];
+/**
+ * struct peci_driver - PECI driver
+ * @driver: inherit device driver
+ * @probe: probe callback
+ * @remove: remove callback
+ * @id_table: PECI device match table to decide which device to bind
+ */
+struct peci_driver {
+ struct device_driver driver;
+ int (*probe)(struct peci_device *device, const struct peci_device_id *id);
+ void (*remove)(struct peci_device *device);
+ const struct peci_device_id *id_table;
+};
+
+static inline struct peci_driver *to_peci_driver(struct device_driver *d)
+{
+ return container_of(d, struct peci_driver, driver);
+}
+
+int __peci_driver_register(struct peci_driver *driver, struct module *owner,
+ const char *mod_name);
+/**
+ * peci_driver_register() - register PECI driver
+ * @driver: the driver to be registered
+ *
+ * PECI drivers that don't need to do anything special in module init should
+ * use the convenience "module_peci_driver" macro instead
+ *
+ * Return: zero on success, else a negative error code.
+ */
+#define peci_driver_register(driver) \
+ __peci_driver_register(driver, THIS_MODULE, KBUILD_MODNAME)
+void peci_driver_unregister(struct peci_driver *driver);
+
+/**
+ * module_peci_driver() - helper macro for registering a modular PECI driver
+ * @__peci_driver: peci_driver struct
+ *
+ * Helper macro for PECI drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only
+ * use this macro once, and calling it replaces module_init() and module_exit()
+ */
+#define module_peci_driver(__peci_driver) \
+ module_driver(__peci_driver, peci_driver_register, peci_driver_unregister)
+
extern struct device_type peci_controller_type;
int peci_controller_scan_devices(struct peci_controller *controller);
diff --git a/drivers/peci/request.c b/drivers/peci/request.c
index 7dee51c50dd2..a49eb351cda3 100644
--- a/drivers/peci/request.c
+++ b/drivers/peci/request.c
@@ -1,13 +1,140 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2021 Intel Corporation
+#include <linux/bug.h>
#include <linux/export.h>
#include <linux/peci.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <asm/unaligned.h>
+
#include "internal.h"
+#define PECI_GET_DIB_CMD 0xf7
+#define PECI_GET_DIB_WR_LEN 1
+#define PECI_GET_DIB_RD_LEN 8
+
+#define PECI_RDPKGCFG_CMD 0xa1
+#define PECI_RDPKGCFG_WR_LEN 5
+#define PECI_RDPKGCFG_RD_LEN_BASE 1
+#define PECI_WRPKGCFG_CMD 0xa5
+#define PECI_WRPKGCFG_WR_LEN_BASE 6
+#define PECI_WRPKGCFG_RD_LEN 1
+
+/* Device Specific Completion Code (CC) Definition */
+#define PECI_CC_SUCCESS 0x40
+#define PECI_CC_NEED_RETRY 0x80
+#define PECI_CC_OUT_OF_RESOURCE 0x81
+#define PECI_CC_UNAVAIL_RESOURCE 0x82
+#define PECI_CC_INVALID_REQ 0x90
+#define PECI_CC_MCA_ERROR 0x91
+#define PECI_CC_CATASTROPHIC_MCA_ERROR 0x93
+#define PECI_CC_FATAL_MCA_ERROR 0x94
+#define PECI_CC_PARITY_ERR_GPSB_OR_PMSB 0x98
+#define PECI_CC_PARITY_ERR_GPSB_OR_PMSB_IERR 0x9B
+#define PECI_CC_PARITY_ERR_GPSB_OR_PMSB_MCA 0x9C
+
+#define PECI_RETRY_BIT BIT(0)
+
+#define PECI_RETRY_TIMEOUT msecs_to_jiffies(700)
+#define PECI_RETRY_INTERVAL_MIN msecs_to_jiffies(1)
+#define PECI_RETRY_INTERVAL_MAX msecs_to_jiffies(128)
+
+static u8 peci_request_data_cc(struct peci_request *req)
+{
+ return req->rx.buf[0];
+}
+
+/**
+ * peci_request_status() - return -errno based on PECI completion code
+ * @req: the PECI request that contains response data with completion code
+ *
+ * It can't be used for Ping(), GetDIB() and GetTemp() - for those commands we
+ * don't expect completion code in the response.
+ *
+ * Return: -errno
+ */
+int peci_request_status(struct peci_request *req)
+{
+ u8 cc = peci_request_data_cc(req);
+
+ if (cc != PECI_CC_SUCCESS)
+ dev_dbg(&req->device->dev, "ret: %#02x\n", cc);
+
+ switch (cc) {
+ case PECI_CC_SUCCESS:
+ return 0;
+ case PECI_CC_NEED_RETRY:
+ case PECI_CC_OUT_OF_RESOURCE:
+ case PECI_CC_UNAVAIL_RESOURCE:
+ return -EAGAIN;
+ case PECI_CC_INVALID_REQ:
+ return -EINVAL;
+ case PECI_CC_MCA_ERROR:
+ case PECI_CC_CATASTROPHIC_MCA_ERROR:
+ case PECI_CC_FATAL_MCA_ERROR:
+ case PECI_CC_PARITY_ERR_GPSB_OR_PMSB:
+ case PECI_CC_PARITY_ERR_GPSB_OR_PMSB_IERR:
+ case PECI_CC_PARITY_ERR_GPSB_OR_PMSB_MCA:
+ return -EIO;
+ }
+
+ WARN_ONCE(1, "Unknown PECI completion code: %#02x\n", cc);
+
+ return -EIO;
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_status, PECI);
+
+static int peci_request_xfer(struct peci_request *req)
+{
+ struct peci_device *device = req->device;
+ struct peci_controller *controller = to_peci_controller(device->dev.parent);
+ int ret;
+
+ mutex_lock(&controller->bus_lock);
+ ret = controller->ops->xfer(controller, device->addr, req);
+ mutex_unlock(&controller->bus_lock);
+
+ return ret;
+}
+
+static int peci_request_xfer_retry(struct peci_request *req)
+{
+ long wait_interval = PECI_RETRY_INTERVAL_MIN;
+ struct peci_device *device = req->device;
+ struct peci_controller *controller = to_peci_controller(device->dev.parent);
+ unsigned long start = jiffies;
+ int ret;
+
+ /* Don't try to use it for ping */
+ if (WARN_ON(req->tx.len == 0))
+ return 0;
+
+ do {
+ ret = peci_request_xfer(req);
+ if (ret) {
+ dev_dbg(&controller->dev, "xfer error: %d\n", ret);
+ return ret;
+ }
+
+ if (peci_request_status(req) != -EAGAIN)
+ return 0;
+
+ /* Set the retry bit to indicate a retry attempt */
+ req->tx.buf[1] |= PECI_RETRY_BIT;
+
+ if (schedule_timeout_interruptible(wait_interval))
+ return -ERESTARTSYS;
+
+ wait_interval = min_t(long, wait_interval * 2, PECI_RETRY_INTERVAL_MAX);
+ } while (time_before(jiffies, start + PECI_RETRY_TIMEOUT));
+
+ dev_dbg(&controller->dev, "request timed out\n");
+
+ return -ETIMEDOUT;
+}
+
/**
* peci_request_alloc() - allocate &struct peci_requests
* @device: PECI device to which request is going to be sent
@@ -53,3 +180,90 @@ void peci_request_free(struct peci_request *req)
kfree(req);
}
EXPORT_SYMBOL_NS_GPL(peci_request_free, PECI);
+
+struct peci_request *peci_xfer_get_dib(struct peci_device *device)
+{
+ struct peci_request *req;
+ int ret;
+
+ req = peci_request_alloc(device, PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN);
+ if (!req)
+ return ERR_PTR(-ENOMEM);
+
+ req->tx.buf[0] = PECI_GET_DIB_CMD;
+
+ ret = peci_request_xfer(req);
+ if (ret) {
+ peci_request_free(req);
+ return ERR_PTR(ret);
+ }
+
+ return req;
+}
+EXPORT_SYMBOL_NS_GPL(peci_xfer_get_dib, PECI);
+
+static struct peci_request *
+__pkg_cfg_read(struct peci_device *device, u8 index, u16 param, u8 len)
+{
+ struct peci_request *req;
+ int ret;
+
+ req = peci_request_alloc(device, PECI_RDPKGCFG_WR_LEN, PECI_RDPKGCFG_RD_LEN_BASE + len);
+ if (!req)
+ return ERR_PTR(-ENOMEM);
+
+ req->tx.buf[0] = PECI_RDPKGCFG_CMD;
+ req->tx.buf[1] = 0;
+ req->tx.buf[2] = index;
+ put_unaligned_le16(param, &req->tx.buf[3]);
+
+ ret = peci_request_xfer_retry(req);
+ if (ret) {
+ peci_request_free(req);
+ return ERR_PTR(ret);
+ }
+
+ return req;
+}
+
+u8 peci_request_data_readb(struct peci_request *req)
+{
+ return req->rx.buf[1];
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_data_readb, PECI);
+
+u16 peci_request_data_readw(struct peci_request *req)
+{
+ return get_unaligned_le16(&req->rx.buf[1]);
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_data_readw, PECI);
+
+u32 peci_request_data_readl(struct peci_request *req)
+{
+ return get_unaligned_le32(&req->rx.buf[1]);
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_data_readl, PECI);
+
+u64 peci_request_data_readq(struct peci_request *req)
+{
+ return get_unaligned_le64(&req->rx.buf[1]);
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_data_readq, PECI);
+
+u64 peci_request_dib_read(struct peci_request *req)
+{
+ return get_unaligned_le64(&req->rx.buf[0]);
+}
+EXPORT_SYMBOL_NS_GPL(peci_request_dib_read, PECI);
+
+#define __read_pkg_config(x, type) \
+struct peci_request *peci_xfer_pkg_cfg_##x(struct peci_device *device, u8 index, u16 param) \
+{ \
+ return __pkg_cfg_read(device, index, param, sizeof(type)); \
+} \
+EXPORT_SYMBOL_NS_GPL(peci_xfer_pkg_cfg_##x, PECI)
+
+__read_pkg_config(readb, u8);
+__read_pkg_config(readw, u16);
+__read_pkg_config(readl, u32);
+__read_pkg_config(readq, u64);
diff --git a/include/linux/peci.h b/include/linux/peci.h
index 7e35673f3786..4eda423ba10c 100644
--- a/include/linux/peci.h
+++ b/include/linux/peci.h
@@ -14,6 +14,14 @@
*/
#define PECI_REQUEST_MAX_BUF_SIZE 32
+#define PECI_PCS_PKG_ID 0 /* Package Identifier Read */
+#define PECI_PKG_ID_CPU_ID 0x0000 /* CPUID Info */
+#define PECI_PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */
+#define PECI_PKG_ID_DEVICE_ID 0x0002 /* Uncore Device ID */
+#define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */
+#define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */
+#define PECI_PKG_ID_MCA_ERROR_LOG 0x0005 /* Machine Check Status */
+
struct peci_controller;
struct peci_request;
@@ -59,6 +67,11 @@ static inline struct peci_controller *to_peci_controller(void *d)
* struct peci_device - PECI device
* @dev: device object to register PECI device to the device model
* @controller: manages the bus segment hosting this PECI device
+ * @info: PECI device characteristics
+ * @info.family: device family
+ * @info.model: device model
+ * @info.peci_revision: PECI revision supported by the PECI device
+ * @info.socket_id: the socket ID represented by the PECI device
* @addr: address used on the PECI bus connected to the parent controller
* @deleted: indicates that PECI device was already deleted
*
@@ -68,6 +81,12 @@ static inline struct peci_controller *to_peci_controller(void *d)
*/
struct peci_device {
struct device dev;
+ struct {
+ u16 family;
+ u8 model;
+ u8 peci_revision;
+ u8 socket_id;
+ } info;
u8 addr;
bool deleted;
};
--
2.31.1
^ permalink raw reply related
* [PATCH v6 04/13] peci: Add core infrastructure
From: Iwona Winiarska @ 2022-01-25 1:10 UTC (permalink / raw)
To: linux-kernel, openbmc, Greg Kroah-Hartman
Cc: devicetree, linux-aspeed, linux-arm-kernel, linux-hwmon,
linux-doc, Rob Herring, Joel Stanley, Andrew Jeffery,
Jean Delvare, Guenter Roeck, Arnd Bergmann, Olof Johansson,
Jonathan Corbet, Borislav Petkov, Pierre-Louis Bossart, Tony Luck,
Andy Shevchenko, Dan Williams, Randy Dunlap, Zev Weiss,
David Muller, Dave Hansen, Billy Tsai, Iwona Winiarska,
Jason M Bills, Jae Hyun Yoo
In-Reply-To: <20220125011104.2480133-1-iwona.winiarska@intel.com>
Intel processors provide access for various services designed to support
processor and DRAM thermal management, platform manageability and
processor interface tuning and diagnostics.
Those services are available via the Platform Environment Control
Interface (PECI) that provides a communication channel between the
processor and the Baseboard Management Controller (BMC) or other
platform management device.
This change introduces PECI subsystem by adding the initial core module
and API for controller drivers.
Co-developed-by: Jason M Bills <jason.m.bills@linux.intel.com>
Signed-off-by: Jason M Bills <jason.m.bills@linux.intel.com>
Co-developed-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
---
MAINTAINERS | 8 ++
drivers/Kconfig | 3 +
drivers/Makefile | 1 +
drivers/peci/Kconfig | 15 ++++
drivers/peci/Makefile | 5 ++
drivers/peci/core.c | 158 ++++++++++++++++++++++++++++++++++++++++
drivers/peci/internal.h | 16 ++++
include/linux/peci.h | 99 +++++++++++++++++++++++++
8 files changed, 305 insertions(+)
create mode 100644 drivers/peci/Kconfig
create mode 100644 drivers/peci/Makefile
create mode 100644 drivers/peci/core.c
create mode 100644 drivers/peci/internal.h
create mode 100644 include/linux/peci.h
diff --git a/MAINTAINERS b/MAINTAINERS
index ea3e6c914384..aa7ae643fdb0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15091,6 +15091,14 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/peaq-wmi.c
+PECI SUBSYSTEM
+M: Iwona Winiarska <iwona.winiarska@intel.com>
+L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
+S: Supported
+F: Documentation/devicetree/bindings/peci/
+F: drivers/peci/
+F: include/linux/peci.h
+
PENSANDO ETHERNET DRIVERS
M: Shannon Nelson <snelson@pensando.io>
M: drivers@pensando.io
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 0d399ddaa185..8d6cd5d08722 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -236,4 +236,7 @@ source "drivers/interconnect/Kconfig"
source "drivers/counter/Kconfig"
source "drivers/most/Kconfig"
+
+source "drivers/peci/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index a110338c860c..020780b6b4d2 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -187,3 +187,4 @@ obj-$(CONFIG_GNSS) += gnss/
obj-$(CONFIG_INTERCONNECT) += interconnect/
obj-$(CONFIG_COUNTER) += counter/
obj-$(CONFIG_MOST) += most/
+obj-$(CONFIG_PECI) += peci/
diff --git a/drivers/peci/Kconfig b/drivers/peci/Kconfig
new file mode 100644
index 000000000000..71a4ad81225a
--- /dev/null
+++ b/drivers/peci/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+menuconfig PECI
+ tristate "PECI support"
+ help
+ The Platform Environment Control Interface (PECI) is an interface
+ that provides a communication channel to Intel processors and
+ chipset components from external monitoring or control devices.
+
+ If you are building a Baseboard Management Controller (BMC) kernel
+ for Intel platform say Y here and also to the specific driver for
+ your adapter(s) below. If unsure say N.
+
+ This support is also available as a module. If so, the module
+ will be called peci.
diff --git a/drivers/peci/Makefile b/drivers/peci/Makefile
new file mode 100644
index 000000000000..e789a354e842
--- /dev/null
+++ b/drivers/peci/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# Core functionality
+peci-y := core.o
+obj-$(CONFIG_PECI) += peci.o
diff --git a/drivers/peci/core.c b/drivers/peci/core.c
new file mode 100644
index 000000000000..73ad0a47fa9d
--- /dev/null
+++ b/drivers/peci/core.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2021 Intel Corporation
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/peci.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+static DEFINE_IDA(peci_controller_ida);
+
+static void peci_controller_dev_release(struct device *dev)
+{
+ struct peci_controller *controller = to_peci_controller(dev);
+
+ mutex_destroy(&controller->bus_lock);
+ ida_free(&peci_controller_ida, controller->id);
+ kfree(controller);
+}
+
+struct device_type peci_controller_type = {
+ .release = peci_controller_dev_release,
+};
+
+static struct peci_controller *peci_controller_alloc(struct device *dev,
+ struct peci_controller_ops *ops)
+{
+ struct peci_controller *controller;
+ int ret;
+
+ if (!ops->xfer)
+ return ERR_PTR(-EINVAL);
+
+ controller = kzalloc(sizeof(*controller), GFP_KERNEL);
+ if (!controller)
+ return ERR_PTR(-ENOMEM);
+
+ ret = ida_alloc_max(&peci_controller_ida, U8_MAX, GFP_KERNEL);
+ if (ret < 0)
+ goto err;
+ controller->id = ret;
+
+ controller->ops = ops;
+
+ controller->dev.parent = dev;
+ controller->dev.bus = &peci_bus_type;
+ controller->dev.type = &peci_controller_type;
+
+ device_initialize(&controller->dev);
+
+ mutex_init(&controller->bus_lock);
+
+ return controller;
+
+err:
+ kfree(controller);
+ return ERR_PTR(ret);
+}
+
+static void unregister_controller(void *_controller)
+{
+ struct peci_controller *controller = _controller;
+
+ device_unregister(&controller->dev);
+
+ fwnode_handle_put(controller->dev.fwnode);
+
+ pm_runtime_disable(&controller->dev);
+}
+
+/**
+ * devm_peci_controller_add() - add PECI controller
+ * @dev: device for devm operations
+ * @ops: pointer to controller specific methods
+ *
+ * In final stage of its probe(), peci_controller driver calls
+ * devm_peci_controller_add() to register itself with the PECI bus.
+ *
+ * Return: Pointer to the newly allocated controller or ERR_PTR() in case of failure.
+ */
+struct peci_controller *devm_peci_controller_add(struct device *dev,
+ struct peci_controller_ops *ops)
+{
+ struct peci_controller *controller;
+ int ret;
+
+ controller = peci_controller_alloc(dev, ops);
+ if (IS_ERR(controller))
+ return controller;
+
+ ret = dev_set_name(&controller->dev, "peci-%d", controller->id);
+ if (ret)
+ goto err_put;
+
+ pm_runtime_no_callbacks(&controller->dev);
+ pm_suspend_ignore_children(&controller->dev, true);
+ pm_runtime_enable(&controller->dev);
+
+ device_set_node(&controller->dev, fwnode_handle_get(dev_fwnode(dev)));
+
+ ret = device_add(&controller->dev);
+ if (ret)
+ goto err_fwnode;
+
+ ret = devm_add_action_or_reset(dev, unregister_controller, controller);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return controller;
+
+err_fwnode:
+ fwnode_handle_put(controller->dev.fwnode);
+
+ pm_runtime_disable(&controller->dev);
+
+err_put:
+ put_device(&controller->dev);
+
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_NS_GPL(devm_peci_controller_add, PECI);
+
+struct bus_type peci_bus_type = {
+ .name = "peci",
+};
+
+static int __init peci_init(void)
+{
+ int ret;
+
+ ret = bus_register(&peci_bus_type);
+ if (ret < 0) {
+ pr_err("peci: failed to register PECI bus type!\n");
+ return ret;
+ }
+
+ return 0;
+}
+module_init(peci_init);
+
+static void __exit peci_exit(void)
+{
+ bus_unregister(&peci_bus_type);
+}
+module_exit(peci_exit);
+
+MODULE_AUTHOR("Jason M Bills <jason.m.bills@linux.intel.com>");
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");
+MODULE_DESCRIPTION("PECI bus core module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/peci/internal.h b/drivers/peci/internal.h
new file mode 100644
index 000000000000..918dea745a86
--- /dev/null
+++ b/drivers/peci/internal.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2018-2021 Intel Corporation */
+
+#ifndef __PECI_INTERNAL_H
+#define __PECI_INTERNAL_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+struct peci_controller;
+
+extern struct bus_type peci_bus_type;
+
+extern struct device_type peci_controller_type;
+
+#endif /* __PECI_INTERNAL_H */
diff --git a/include/linux/peci.h b/include/linux/peci.h
new file mode 100644
index 000000000000..26e0a4e73b50
--- /dev/null
+++ b/include/linux/peci.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2018-2021 Intel Corporation */
+
+#ifndef __LINUX_PECI_H
+#define __LINUX_PECI_H
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+/*
+ * Currently we don't support any PECI command over 32 bytes.
+ */
+#define PECI_REQUEST_MAX_BUF_SIZE 32
+
+struct peci_controller;
+struct peci_request;
+
+/**
+ * struct peci_controller_ops - PECI controller specific methods
+ * @xfer: PECI transfer function
+ *
+ * PECI controllers may have different hardware interfaces - the drivers
+ * implementing PECI controllers can use this structure to abstract away those
+ * differences by exposing a common interface for PECI core.
+ */
+struct peci_controller_ops {
+ int (*xfer)(struct peci_controller *controller, u8 addr, struct peci_request *req);
+};
+
+/**
+ * struct peci_controller - PECI controller
+ * @dev: device object to register PECI controller to the device model
+ * @ops: pointer to device specific controller operations
+ * @bus_lock: lock used to protect multiple callers
+ * @id: PECI controller ID
+ *
+ * PECI controllers usually connect to their drivers using non-PECI bus,
+ * such as the platform bus.
+ * Each PECI controller can communicate with one or more PECI devices.
+ */
+struct peci_controller {
+ struct device dev;
+ struct peci_controller_ops *ops;
+ struct mutex bus_lock; /* held for the duration of xfer */
+ u8 id;
+};
+
+struct peci_controller *devm_peci_controller_add(struct device *parent,
+ struct peci_controller_ops *ops);
+
+static inline struct peci_controller *to_peci_controller(void *d)
+{
+ return container_of(d, struct peci_controller, dev);
+}
+
+/**
+ * struct peci_device - PECI device
+ * @dev: device object to register PECI device to the device model
+ * @controller: manages the bus segment hosting this PECI device
+ * @addr: address used on the PECI bus connected to the parent controller
+ *
+ * A peci_device identifies a single device (i.e. CPU) connected to a PECI bus.
+ * The behaviour exposed to the rest of the system is defined by the PECI driver
+ * managing the device.
+ */
+struct peci_device {
+ struct device dev;
+ u8 addr;
+};
+
+static inline struct peci_device *to_peci_device(struct device *d)
+{
+ return container_of(d, struct peci_device, dev);
+}
+
+/**
+ * struct peci_request - PECI request
+ * @device: PECI device to which the request is sent
+ * @tx: TX buffer specific data
+ * @tx.buf: TX buffer
+ * @tx.len: transfer data length in bytes
+ * @rx: RX buffer specific data
+ * @rx.buf: RX buffer
+ * @rx.len: received data length in bytes
+ *
+ * A peci_request represents a request issued by PECI originator (TX) and
+ * a response received from PECI responder (RX).
+ */
+struct peci_request {
+ struct peci_device *device;
+ struct {
+ u8 buf[PECI_REQUEST_MAX_BUF_SIZE];
+ u8 len;
+ } rx, tx;
+};
+
+#endif /* __LINUX_PECI_H */
--
2.31.1
^ permalink raw reply related
* [PATCH v6 07/13] peci: Add sysfs interface for PECI bus
From: Iwona Winiarska @ 2022-01-25 1:10 UTC (permalink / raw)
To: linux-kernel, openbmc, Greg Kroah-Hartman
Cc: devicetree, linux-aspeed, linux-arm-kernel, linux-hwmon,
linux-doc, Rob Herring, Joel Stanley, Andrew Jeffery,
Jean Delvare, Guenter Roeck, Arnd Bergmann, Olof Johansson,
Jonathan Corbet, Borislav Petkov, Pierre-Louis Bossart, Tony Luck,
Andy Shevchenko, Dan Williams, Randy Dunlap, Zev Weiss,
David Muller, Dave Hansen, Billy Tsai, Iwona Winiarska
In-Reply-To: <20220125011104.2480133-1-iwona.winiarska@intel.com>
PECI devices may not be discoverable at the time when PECI controller is
being added (e.g. BMC can boot up when the Host system is still in S5).
Since we currently don't have the capabilities to figure out the Host
system state inside the PECI subsystem itself, we have to rely on
userspace to do it for us.
In the future, PECI subsystem may be expanded with mechanisms that allow
us to avoid depending on userspace interaction (e.g. CPU presence could
be detected using GPIO, and the information on whether it's discoverable
could be obtained over IPMI).
Unfortunately, those methods may ultimately not be available (support
will vary from platform to platform), which means that we still need
platform independent method triggered by userspace.
Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com>
---
Documentation/ABI/testing/sysfs-bus-peci | 16 +++++
drivers/peci/Makefile | 2 +-
drivers/peci/core.c | 3 +-
drivers/peci/device.c | 1 +
drivers/peci/internal.h | 5 ++
drivers/peci/sysfs.c | 82 ++++++++++++++++++++++++
6 files changed, 107 insertions(+), 2 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-bus-peci
create mode 100644 drivers/peci/sysfs.c
diff --git a/Documentation/ABI/testing/sysfs-bus-peci b/Documentation/ABI/testing/sysfs-bus-peci
new file mode 100644
index 000000000000..56c2b2216bbd
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-peci
@@ -0,0 +1,16 @@
+What: /sys/bus/peci/rescan
+Date: July 2021
+KernelVersion: 5.15
+Contact: Iwona Winiarska <iwona.winiarska@intel.com>
+Description:
+ Writing a non-zero value to this attribute will
+ initiate scan for PECI devices on all PECI controllers
+ in the system.
+
+What: /sys/bus/peci/devices/<controller_id>-<device_addr>/remove
+Date: July 2021
+KernelVersion: 5.15
+Contact: Iwona Winiarska <iwona.winiarska@intel.com>
+Description:
+ Writing a non-zero value to this attribute will
+ remove the PECI device and any of its children.
diff --git a/drivers/peci/Makefile b/drivers/peci/Makefile
index c5f9d3fe21bb..917f689e147a 100644
--- a/drivers/peci/Makefile
+++ b/drivers/peci/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
# Core functionality
-peci-y := core.o request.o device.o
+peci-y := core.o request.o device.o sysfs.o
obj-$(CONFIG_PECI) += peci.o
# Hardware specific bus drivers
diff --git a/drivers/peci/core.c b/drivers/peci/core.c
index c3361e6e043a..e993615cf521 100644
--- a/drivers/peci/core.c
+++ b/drivers/peci/core.c
@@ -29,7 +29,7 @@ struct device_type peci_controller_type = {
.release = peci_controller_dev_release,
};
-static int peci_controller_scan_devices(struct peci_controller *controller)
+int peci_controller_scan_devices(struct peci_controller *controller)
{
int ret;
u8 addr;
@@ -162,6 +162,7 @@ EXPORT_SYMBOL_NS_GPL(devm_peci_controller_add, PECI);
struct bus_type peci_bus_type = {
.name = "peci",
+ .bus_groups = peci_bus_groups,
};
static int __init peci_init(void)
diff --git a/drivers/peci/device.c b/drivers/peci/device.c
index 2b3a2d893aaf..d10ed1cfcd48 100644
--- a/drivers/peci/device.c
+++ b/drivers/peci/device.c
@@ -116,5 +116,6 @@ static void peci_device_release(struct device *dev)
}
struct device_type peci_device_type = {
+ .groups = peci_device_groups,
.release = peci_device_release,
};
diff --git a/drivers/peci/internal.h b/drivers/peci/internal.h
index 57d11a902c5d..978e12c8e1d3 100644
--- a/drivers/peci/internal.h
+++ b/drivers/peci/internal.h
@@ -8,6 +8,7 @@
#include <linux/types.h>
struct peci_controller;
+struct attribute_group;
struct peci_device;
struct peci_request;
@@ -19,12 +20,16 @@ struct peci_request *peci_request_alloc(struct peci_device *device, u8 tx_len, u
void peci_request_free(struct peci_request *req);
extern struct device_type peci_device_type;
+extern const struct attribute_group *peci_device_groups[];
int peci_device_create(struct peci_controller *controller, u8 addr);
void peci_device_destroy(struct peci_device *device);
extern struct bus_type peci_bus_type;
+extern const struct attribute_group *peci_bus_groups[];
extern struct device_type peci_controller_type;
+int peci_controller_scan_devices(struct peci_controller *controller);
+
#endif /* __PECI_INTERNAL_H */
diff --git a/drivers/peci/sysfs.c b/drivers/peci/sysfs.c
new file mode 100644
index 000000000000..db9ef05776e3
--- /dev/null
+++ b/drivers/peci/sysfs.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2021 Intel Corporation
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/peci.h>
+
+#include "internal.h"
+
+static int rescan_controller(struct device *dev, void *data)
+{
+ if (dev->type != &peci_controller_type)
+ return 0;
+
+ return peci_controller_scan_devices(to_peci_controller(dev));
+}
+
+static ssize_t rescan_store(struct bus_type *bus, const char *buf, size_t count)
+{
+ bool res;
+ int ret;
+
+ ret = kstrtobool(buf, &res);
+ if (ret)
+ return ret;
+
+ if (!res)
+ return count;
+
+ ret = bus_for_each_dev(&peci_bus_type, NULL, NULL, rescan_controller);
+ if (ret)
+ return ret;
+
+ return count;
+}
+static BUS_ATTR_WO(rescan);
+
+static struct attribute *peci_bus_attrs[] = {
+ &bus_attr_rescan.attr,
+ NULL
+};
+
+static const struct attribute_group peci_bus_group = {
+ .attrs = peci_bus_attrs,
+};
+
+const struct attribute_group *peci_bus_groups[] = {
+ &peci_bus_group,
+ NULL
+};
+
+static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct peci_device *device = to_peci_device(dev);
+ bool res;
+ int ret;
+
+ ret = kstrtobool(buf, &res);
+ if (ret)
+ return ret;
+
+ if (res && device_remove_file_self(dev, attr))
+ peci_device_destroy(device);
+
+ return count;
+}
+static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0200, NULL, remove_store);
+
+static struct attribute *peci_device_attrs[] = {
+ &dev_attr_remove.attr,
+ NULL
+};
+
+static const struct attribute_group peci_device_group = {
+ .attrs = peci_device_attrs,
+};
+
+const struct attribute_group *peci_device_groups[] = {
+ &peci_device_group,
+ NULL
+};
--
2.31.1
^ permalink raw reply related
* [PATCH 0/3] Add support for the HP TouchPad
From: Ben Wolsieffer @ 2022-01-25 2:07 UTC (permalink / raw)
Cc: Ben Wolsieffer, Andy Gross, Bjorn Andersson, Rob Herring,
Arnd Bergmann, Olof Johansson, soc, Stephen Boyd, linux-arm-msm,
devicetree, linux-kernel, linux-arm-kernel
This patchset adds basic support for the HP TouchPad (codename
"tenderloin") tablet. I started with a copy of the AQP8060 Dragonboard
device tree and made the necessary changes as a separate patch.
Ben Wolsieffer (3):
ARM: dts: qcom: add HP TouchPad (tenderloin)
dt-bindings: arm: qcom: document HP TouchPad
ARM: dts: qcom: basic HP TouchPad support
.../devicetree/bindings/arm/qcom.yaml | 1 +
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/qcom-apq8060-tenderloin.dts | 478 ++++++++++++++++++
3 files changed, 480 insertions(+)
create mode 100644 arch/arm/boot/dts/qcom-apq8060-tenderloin.dts
--
2.34.1
^ permalink raw reply
* [PATCH v6 10/13] hwmon: peci: Add cputemp driver
From: Iwona Winiarska @ 2022-01-25 1:11 UTC (permalink / raw)
To: linux-kernel, openbmc, Greg Kroah-Hartman
Cc: devicetree, linux-aspeed, linux-arm-kernel, linux-hwmon,
linux-doc, Rob Herring, Joel Stanley, Andrew Jeffery,
Jean Delvare, Guenter Roeck, Arnd Bergmann, Olof Johansson,
Jonathan Corbet, Borislav Petkov, Pierre-Louis Bossart, Tony Luck,
Andy Shevchenko, Dan Williams, Randy Dunlap, Zev Weiss,
David Muller, Dave Hansen, Billy Tsai, Iwona Winiarska,
Jae Hyun Yoo
In-Reply-To: <20220125011104.2480133-1-iwona.winiarska@intel.com>
Add peci-cputemp driver for Digital Thermal Sensor (DTS) thermal
readings of the processor package and processor cores that are
accessible via the PECI interface.
The main use case for the driver (and PECI interface) is out-of-band
management, where we're able to obtain the DTS readings from an external
entity connected with PECI, e.g. BMC on server platforms.
Co-developed-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
---
MAINTAINERS | 6 +
drivers/hwmon/Kconfig | 2 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/peci/Kconfig | 18 ++
drivers/hwmon/peci/Makefile | 5 +
drivers/hwmon/peci/common.h | 58 ++++
drivers/hwmon/peci/cputemp.c | 592 +++++++++++++++++++++++++++++++++++
7 files changed, 682 insertions(+)
create mode 100644 drivers/hwmon/peci/Kconfig
create mode 100644 drivers/hwmon/peci/Makefile
create mode 100644 drivers/hwmon/peci/common.h
create mode 100644 drivers/hwmon/peci/cputemp.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 7c31e29c885a..369ac3524f33 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15099,6 +15099,12 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/peaq-wmi.c
+PECI HARDWARE MONITORING DRIVERS
+M: Iwona Winiarska <iwona.winiarska@intel.com>
+L: linux-hwmon@vger.kernel.org
+S: Supported
+F: drivers/hwmon/peci/
+
PECI SUBSYSTEM
M: Iwona Winiarska <iwona.winiarska@intel.com>
L: openbmc@lists.ozlabs.org (moderated for non-subscribers)
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 8df25f1079ba..af6c3bd65ebd 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1538,6 +1538,8 @@ config SENSORS_PCF8591
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
+source "drivers/hwmon/peci/Kconfig"
+
source "drivers/hwmon/pmbus/Kconfig"
config SENSORS_PWM_FAN
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 185f946d698b..6139e5a5aa00 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -208,6 +208,7 @@ obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o
obj-$(CONFIG_SENSORS_OCC) += occ/
+obj-$(CONFIG_SENSORS_PECI) += peci/
obj-$(CONFIG_PMBUS) += pmbus/
ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG
diff --git a/drivers/hwmon/peci/Kconfig b/drivers/hwmon/peci/Kconfig
new file mode 100644
index 000000000000..e10eed68d70a
--- /dev/null
+++ b/drivers/hwmon/peci/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config SENSORS_PECI_CPUTEMP
+ tristate "PECI CPU temperature monitoring client"
+ depends on PECI
+ select SENSORS_PECI
+ select PECI_CPU
+ help
+ If you say yes here you get support for the generic Intel PECI
+ cputemp driver which provides Digital Thermal Sensor (DTS) thermal
+ readings of the CPU package and CPU cores that are accessible via
+ the processor PECI interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called peci-cputemp.
+
+config SENSORS_PECI
+ tristate
diff --git a/drivers/hwmon/peci/Makefile b/drivers/hwmon/peci/Makefile
new file mode 100644
index 000000000000..e8a0ada5ab1f
--- /dev/null
+++ b/drivers/hwmon/peci/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+peci-cputemp-y := cputemp.o
+
+obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o
diff --git a/drivers/hwmon/peci/common.h b/drivers/hwmon/peci/common.h
new file mode 100644
index 000000000000..734506b0eca2
--- /dev/null
+++ b/drivers/hwmon/peci/common.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2021 Intel Corporation */
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+#ifndef __PECI_HWMON_COMMON_H
+#define __PECI_HWMON_COMMON_H
+
+#define PECI_HWMON_UPDATE_INTERVAL HZ
+
+/**
+ * struct peci_sensor_state - PECI state information
+ * @valid: flag to indicate the sensor value is valid
+ * @last_updated: time of the last update in jiffies
+ * @lock: mutex to protect sensor access
+ */
+struct peci_sensor_state {
+ bool valid;
+ unsigned long last_updated;
+ struct mutex lock; /* protect sensor access */
+};
+
+/**
+ * struct peci_sensor_data - PECI sensor information
+ * @value: sensor value in milli units
+ * @state: sensor update state
+ */
+
+struct peci_sensor_data {
+ s32 value;
+ struct peci_sensor_state state;
+};
+
+/**
+ * peci_sensor_need_update() - check whether sensor update is needed or not
+ * @sensor: pointer to sensor data struct
+ *
+ * Return: true if update is needed, false if not.
+ */
+
+static inline bool peci_sensor_need_update(struct peci_sensor_state *state)
+{
+ return !state->valid ||
+ time_after(jiffies, state->last_updated + PECI_HWMON_UPDATE_INTERVAL);
+}
+
+/**
+ * peci_sensor_mark_updated() - mark the sensor is updated
+ * @sensor: pointer to sensor data struct
+ */
+static inline void peci_sensor_mark_updated(struct peci_sensor_state *state)
+{
+ state->valid = true;
+ state->last_updated = jiffies;
+}
+
+#endif /* __PECI_HWMON_COMMON_H */
diff --git a/drivers/hwmon/peci/cputemp.c b/drivers/hwmon/peci/cputemp.c
new file mode 100644
index 000000000000..12156328f5cf
--- /dev/null
+++ b/drivers/hwmon/peci/cputemp.c
@@ -0,0 +1,592 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2021 Intel Corporation
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/peci.h>
+#include <linux/peci-cpu.h>
+#include <linux/units.h>
+
+#include "common.h"
+
+#define CORE_NUMS_MAX 64
+
+#define BASE_CHANNEL_NUMS 5
+#define CPUTEMP_CHANNEL_NUMS (BASE_CHANNEL_NUMS + CORE_NUMS_MAX)
+
+#define TEMP_TARGET_FAN_TEMP_MASK GENMASK(15, 8)
+#define TEMP_TARGET_REF_TEMP_MASK GENMASK(23, 16)
+#define TEMP_TARGET_TJ_OFFSET_MASK GENMASK(29, 24)
+
+#define DTS_MARGIN_MASK GENMASK(15, 0)
+#define PCS_MODULE_TEMP_MASK GENMASK(15, 0)
+
+struct resolved_cores_reg {
+ u8 bus;
+ u8 dev;
+ u8 func;
+ u8 offset;
+};
+
+struct cpu_info {
+ struct resolved_cores_reg *reg;
+ u8 min_peci_revision;
+ s32 (*thermal_margin_to_millidegree)(u16 val);
+};
+
+struct peci_temp_target {
+ s32 tcontrol;
+ s32 tthrottle;
+ s32 tjmax;
+ struct peci_sensor_state state;
+};
+
+enum peci_temp_target_type {
+ tcontrol_type,
+ tthrottle_type,
+ tjmax_type,
+ crit_hyst_type,
+};
+
+struct peci_cputemp {
+ struct peci_device *peci_dev;
+ struct device *dev;
+ const char *name;
+ const struct cpu_info *gen_info;
+ struct {
+ struct peci_temp_target target;
+ struct peci_sensor_data die;
+ struct peci_sensor_data dts;
+ struct peci_sensor_data core[CORE_NUMS_MAX];
+ } temp;
+ const char **coretemp_label;
+ DECLARE_BITMAP(core_mask, CORE_NUMS_MAX);
+};
+
+enum cputemp_channels {
+ channel_die,
+ channel_dts,
+ channel_tcontrol,
+ channel_tthrottle,
+ channel_tjmax,
+ channel_core,
+};
+
+static const char * const cputemp_label[BASE_CHANNEL_NUMS] = {
+ "Die",
+ "DTS",
+ "Tcontrol",
+ "Tthrottle",
+ "Tjmax",
+};
+
+static int update_temp_target(struct peci_cputemp *priv)
+{
+ s32 tthrottle_offset, tcontrol_margin;
+ u32 pcs;
+ int ret;
+
+ if (!peci_sensor_need_update(&priv->temp.target.state))
+ return 0;
+
+ ret = peci_pcs_read(priv->peci_dev, PECI_PCS_TEMP_TARGET, 0, &pcs);
+ if (ret)
+ return ret;
+
+ priv->temp.target.tjmax =
+ FIELD_GET(TEMP_TARGET_REF_TEMP_MASK, pcs) * MILLIDEGREE_PER_DEGREE;
+
+ tcontrol_margin = FIELD_GET(TEMP_TARGET_FAN_TEMP_MASK, pcs);
+ tcontrol_margin = sign_extend32(tcontrol_margin, 7) * MILLIDEGREE_PER_DEGREE;
+ priv->temp.target.tcontrol = priv->temp.target.tjmax - tcontrol_margin;
+
+ tthrottle_offset = FIELD_GET(TEMP_TARGET_TJ_OFFSET_MASK, pcs) * MILLIDEGREE_PER_DEGREE;
+ priv->temp.target.tthrottle = priv->temp.target.tjmax - tthrottle_offset;
+
+ peci_sensor_mark_updated(&priv->temp.target.state);
+
+ return 0;
+}
+
+static int get_temp_target(struct peci_cputemp *priv, enum peci_temp_target_type type, long *val)
+{
+ int ret;
+
+ mutex_lock(&priv->temp.target.state.lock);
+
+ ret = update_temp_target(priv);
+ if (ret)
+ goto unlock;
+
+ switch (type) {
+ case tcontrol_type:
+ *val = priv->temp.target.tcontrol;
+ break;
+ case tthrottle_type:
+ *val = priv->temp.target.tthrottle;
+ break;
+ case tjmax_type:
+ *val = priv->temp.target.tjmax;
+ break;
+ case crit_hyst_type:
+ *val = priv->temp.target.tjmax - priv->temp.target.tcontrol;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+unlock:
+ mutex_unlock(&priv->temp.target.state.lock);
+
+ return ret;
+}
+
+/*
+ * Error codes:
+ * 0x8000: General sensor error
+ * 0x8001: Reserved
+ * 0x8002: Underflow on reading value
+ * 0x8003-0x81ff: Reserved
+ */
+static bool dts_valid(u16 val)
+{
+ return val < 0x8000 || val > 0x81ff;
+}
+
+/*
+ * Processors return a value of DTS reading in S10.6 fixed point format
+ * (16 bits: 10-bit signed magnitude, 6-bit fraction).
+ */
+static s32 dts_ten_dot_six_to_millidegree(u16 val)
+{
+ return sign_extend32(val, 15) * MILLIDEGREE_PER_DEGREE / 64;
+}
+
+/*
+ * For older processors, thermal margin reading is returned in S8.8 fixed
+ * point format (16 bits: 8-bit signed magnitude, 8-bit fraction).
+ */
+static s32 dts_eight_dot_eight_to_millidegree(u16 val)
+{
+ return sign_extend32(val, 15) * MILLIDEGREE_PER_DEGREE / 256;
+}
+
+static int get_die_temp(struct peci_cputemp *priv, long *val)
+{
+ int ret = 0;
+ long tjmax;
+ u16 temp;
+
+ mutex_lock(&priv->temp.die.state.lock);
+ if (!peci_sensor_need_update(&priv->temp.die.state))
+ goto skip_update;
+
+ ret = peci_temp_read(priv->peci_dev, &temp);
+ if (ret)
+ goto err_unlock;
+
+ if (!dts_valid(temp)) {
+ ret = -EIO;
+ goto err_unlock;
+ }
+
+ ret = get_temp_target(priv, tjmax_type, &tjmax);
+ if (ret)
+ goto err_unlock;
+
+ priv->temp.die.value = (s32)tjmax + dts_ten_dot_six_to_millidegree(temp);
+
+ peci_sensor_mark_updated(&priv->temp.die.state);
+
+skip_update:
+ *val = priv->temp.die.value;
+err_unlock:
+ mutex_unlock(&priv->temp.die.state.lock);
+ return ret;
+}
+
+static int get_dts(struct peci_cputemp *priv, long *val)
+{
+ int ret = 0;
+ u16 thermal_margin;
+ long tcontrol;
+ u32 pcs;
+
+ mutex_lock(&priv->temp.dts.state.lock);
+ if (!peci_sensor_need_update(&priv->temp.dts.state))
+ goto skip_update;
+
+ ret = peci_pcs_read(priv->peci_dev, PECI_PCS_THERMAL_MARGIN, 0, &pcs);
+ if (ret)
+ goto err_unlock;
+
+ thermal_margin = FIELD_GET(DTS_MARGIN_MASK, pcs);
+ if (!dts_valid(thermal_margin)) {
+ ret = -EIO;
+ goto err_unlock;
+ }
+
+ ret = get_temp_target(priv, tcontrol_type, &tcontrol);
+ if (ret)
+ goto err_unlock;
+
+ /* Note that the tcontrol should be available before calling it */
+ priv->temp.dts.value =
+ (s32)tcontrol - priv->gen_info->thermal_margin_to_millidegree(thermal_margin);
+
+ peci_sensor_mark_updated(&priv->temp.dts.state);
+
+skip_update:
+ *val = priv->temp.dts.value;
+err_unlock:
+ mutex_unlock(&priv->temp.dts.state.lock);
+ return ret;
+}
+
+static int get_core_temp(struct peci_cputemp *priv, int core_index, long *val)
+{
+ int ret = 0;
+ u16 core_dts_margin;
+ long tjmax;
+ u32 pcs;
+
+ mutex_lock(&priv->temp.core[core_index].state.lock);
+ if (!peci_sensor_need_update(&priv->temp.core[core_index].state))
+ goto skip_update;
+
+ ret = peci_pcs_read(priv->peci_dev, PECI_PCS_MODULE_TEMP, core_index, &pcs);
+ if (ret)
+ goto err_unlock;
+
+ core_dts_margin = FIELD_GET(PCS_MODULE_TEMP_MASK, pcs);
+ if (!dts_valid(core_dts_margin)) {
+ ret = -EIO;
+ goto err_unlock;
+ }
+
+ ret = get_temp_target(priv, tjmax_type, &tjmax);
+ if (ret)
+ goto err_unlock;
+
+ /* Note that the tjmax should be available before calling it */
+ priv->temp.core[core_index].value =
+ (s32)tjmax + dts_ten_dot_six_to_millidegree(core_dts_margin);
+
+ peci_sensor_mark_updated(&priv->temp.core[core_index].state);
+
+skip_update:
+ *val = priv->temp.core[core_index].value;
+err_unlock:
+ mutex_unlock(&priv->temp.core[core_index].state.lock);
+ return ret;
+}
+
+static int cputemp_read_string(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ struct peci_cputemp *priv = dev_get_drvdata(dev);
+
+ if (attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+
+ *str = channel < channel_core ?
+ cputemp_label[channel] : priv->coretemp_label[channel - channel_core];
+
+ return 0;
+}
+
+static int cputemp_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct peci_cputemp *priv = dev_get_drvdata(dev);
+
+ switch (attr) {
+ case hwmon_temp_input:
+ switch (channel) {
+ case channel_die:
+ return get_die_temp(priv, val);
+ case channel_dts:
+ return get_dts(priv, val);
+ case channel_tcontrol:
+ return get_temp_target(priv, tcontrol_type, val);
+ case channel_tthrottle:
+ return get_temp_target(priv, tthrottle_type, val);
+ case channel_tjmax:
+ return get_temp_target(priv, tjmax_type, val);
+ default:
+ return get_core_temp(priv, channel - channel_core, val);
+ }
+ break;
+ case hwmon_temp_max:
+ return get_temp_target(priv, tcontrol_type, val);
+ case hwmon_temp_crit:
+ return get_temp_target(priv, tjmax_type, val);
+ case hwmon_temp_crit_hyst:
+ return get_temp_target(priv, crit_hyst_type, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static umode_t cputemp_is_visible(const void *data, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct peci_cputemp *priv = data;
+
+ if (channel > CPUTEMP_CHANNEL_NUMS)
+ return 0;
+
+ if (channel < channel_core)
+ return 0444;
+
+ if (test_bit(channel - channel_core, priv->core_mask))
+ return 0444;
+
+ return 0;
+}
+
+static int init_core_mask(struct peci_cputemp *priv)
+{
+ struct peci_device *peci_dev = priv->peci_dev;
+ struct resolved_cores_reg *reg = priv->gen_info->reg;
+ u64 core_mask;
+ u32 data;
+ int ret;
+
+ /* Get the RESOLVED_CORES register value */
+ switch (peci_dev->info.model) {
+ case INTEL_FAM6_ICELAKE_X:
+ case INTEL_FAM6_ICELAKE_D:
+ ret = peci_ep_pci_local_read(peci_dev, 0, reg->bus, reg->dev,
+ reg->func, reg->offset + 4, &data);
+ if (ret)
+ return ret;
+
+ core_mask = (u64)data << 32;
+
+ ret = peci_ep_pci_local_read(peci_dev, 0, reg->bus, reg->dev,
+ reg->func, reg->offset, &data);
+ if (ret)
+ return ret;
+
+ core_mask |= data;
+
+ break;
+ default:
+ ret = peci_pci_local_read(peci_dev, reg->bus, reg->dev,
+ reg->func, reg->offset, &data);
+ if (ret)
+ return ret;
+
+ core_mask = data;
+
+ break;
+ }
+
+ if (!core_mask)
+ return -EIO;
+
+ bitmap_from_u64(priv->core_mask, core_mask);
+
+ return 0;
+}
+
+static int create_temp_label(struct peci_cputemp *priv)
+{
+ unsigned long core_max = find_last_bit(priv->core_mask, CORE_NUMS_MAX);
+ int i;
+
+ priv->coretemp_label = devm_kzalloc(priv->dev, core_max * sizeof(char *), GFP_KERNEL);
+ if (!priv->coretemp_label)
+ return -ENOMEM;
+
+ for_each_set_bit(i, priv->core_mask, CORE_NUMS_MAX) {
+ priv->coretemp_label[i] = devm_kasprintf(priv->dev, GFP_KERNEL, "Core %d", i);
+ if (!priv->coretemp_label[i])
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void check_resolved_cores(struct peci_cputemp *priv)
+{
+ /*
+ * Failure to resolve cores is non-critical, we're still able to
+ * provide other sensor data.
+ */
+
+ if (init_core_mask(priv))
+ return;
+
+ if (create_temp_label(priv))
+ bitmap_zero(priv->core_mask, CORE_NUMS_MAX);
+}
+
+static void sensor_init(struct peci_cputemp *priv)
+{
+ int i;
+
+ mutex_init(&priv->temp.target.state.lock);
+ mutex_init(&priv->temp.die.state.lock);
+ mutex_init(&priv->temp.dts.state.lock);
+
+ for_each_set_bit(i, priv->core_mask, CORE_NUMS_MAX)
+ mutex_init(&priv->temp.core[i].state.lock);
+}
+
+static const struct hwmon_ops peci_cputemp_ops = {
+ .is_visible = cputemp_is_visible,
+ .read_string = cputemp_read_string,
+ .read = cputemp_read,
+};
+
+static const u32 peci_cputemp_temp_channel_config[] = {
+ /* Die temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_CRIT_HYST,
+ /* DTS margin */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_CRIT_HYST,
+ /* Tcontrol temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT,
+ /* Tthrottle temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT,
+ /* Tjmax temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT,
+ /* Core temperature - for all core channels */
+ [channel_core ... CPUTEMP_CHANNEL_NUMS - 1] = HWMON_T_LABEL | HWMON_T_INPUT,
+ 0
+};
+
+static const struct hwmon_channel_info peci_cputemp_temp_channel = {
+ .type = hwmon_temp,
+ .config = peci_cputemp_temp_channel_config,
+};
+
+static const struct hwmon_channel_info *peci_cputemp_info[] = {
+ &peci_cputemp_temp_channel,
+ NULL
+};
+
+static const struct hwmon_chip_info peci_cputemp_chip_info = {
+ .ops = &peci_cputemp_ops,
+ .info = peci_cputemp_info,
+};
+
+static int peci_cputemp_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct device *dev = &adev->dev;
+ struct peci_device *peci_dev = to_peci_device(dev->parent);
+ struct peci_cputemp *priv;
+ struct device *hwmon_dev;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->name = devm_kasprintf(dev, GFP_KERNEL, "peci_cputemp.cpu%d",
+ peci_dev->info.socket_id);
+ if (!priv->name)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->peci_dev = peci_dev;
+ priv->gen_info = (const struct cpu_info *)id->driver_data;
+
+ /*
+ * This is just a sanity check. Since we're using commands that are
+ * guaranteed to be supported on a given platform, we should never see
+ * revision lower than expected.
+ */
+ if (peci_dev->info.peci_revision < priv->gen_info->min_peci_revision)
+ dev_warn(priv->dev,
+ "Unexpected PECI revision %#x, some features may be unavailable\n",
+ peci_dev->info.peci_revision);
+
+ check_resolved_cores(priv);
+
+ sensor_init(priv);
+
+ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev, priv->name,
+ priv, &peci_cputemp_chip_info, NULL);
+
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+/*
+ * RESOLVED_CORES PCI configuration register may have different location on
+ * different platforms.
+ */
+static struct resolved_cores_reg resolved_cores_reg_hsx = {
+ .bus = 1,
+ .dev = 30,
+ .func = 3,
+ .offset = 0xb4,
+};
+
+static struct resolved_cores_reg resolved_cores_reg_icx = {
+ .bus = 14,
+ .dev = 30,
+ .func = 3,
+ .offset = 0xd0,
+};
+
+static const struct cpu_info cpu_hsx = {
+ .reg = &resolved_cores_reg_hsx,
+ .min_peci_revision = 0x33,
+ .thermal_margin_to_millidegree = &dts_eight_dot_eight_to_millidegree,
+};
+
+static const struct cpu_info cpu_icx = {
+ .reg = &resolved_cores_reg_icx,
+ .min_peci_revision = 0x40,
+ .thermal_margin_to_millidegree = &dts_ten_dot_six_to_millidegree,
+};
+
+static const struct auxiliary_device_id peci_cputemp_ids[] = {
+ {
+ .name = "peci_cpu.cputemp.hsx",
+ .driver_data = (kernel_ulong_t)&cpu_hsx,
+ },
+ {
+ .name = "peci_cpu.cputemp.bdx",
+ .driver_data = (kernel_ulong_t)&cpu_hsx,
+ },
+ {
+ .name = "peci_cpu.cputemp.bdxd",
+ .driver_data = (kernel_ulong_t)&cpu_hsx,
+ },
+ {
+ .name = "peci_cpu.cputemp.skx",
+ .driver_data = (kernel_ulong_t)&cpu_hsx,
+ },
+ {
+ .name = "peci_cpu.cputemp.icx",
+ .driver_data = (kernel_ulong_t)&cpu_icx,
+ },
+ {
+ .name = "peci_cpu.cputemp.icxd",
+ .driver_data = (kernel_ulong_t)&cpu_icx,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(auxiliary, peci_cputemp_ids);
+
+static struct auxiliary_driver peci_cputemp_driver = {
+ .probe = peci_cputemp_probe,
+ .id_table = peci_cputemp_ids,
+};
+
+module_auxiliary_driver(peci_cputemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");
+MODULE_DESCRIPTION("PECI cputemp driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(PECI_CPU);
--
2.31.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox