Merge 1b1391b9c4 ("Merge tag 'block-6.18-20251009' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux") into android-mainline
Steps on the way to v6.18-rc1 Change-Id: I0878507bc2b5daff8aae875d48cf518050fa1cf1 Signed-off-by: Carlos Llamas <cmllamas@google.com>
This commit is contained in:
commit
3b55e4052d
91 files changed
+1314
-733
No files matched your search
@@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/hisilicon,hix5hd2-i2c.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: I2C for HiSilicon hix5hd2 chipset platform
|
||||
|
||||
maintainers:
|
||||
- Wei Yan <sledge.yanwei@huawei.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- hisilicon,hix5hd2-i2c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-frequency:
|
||||
description: Desired I2C bus frequency in Hz
|
||||
default: 100000
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/hix5hd2-clock.h>
|
||||
|
||||
i2c@f8b10000 {
|
||||
compatible = "hisilicon,hix5hd2-i2c";
|
||||
reg = <0xf8b10000 0x1000>;
|
||||
interrupts = <0 38 4>;
|
||||
clocks = <&clock HIX5HD2_I2C0_RST>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
I2C for Hisilicon hix5hd2 chipset platform
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be "hisilicon,hix5hd2-i2c"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: interrupt number to the cpu.
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- clocks: phandles to input clocks.
|
||||
|
||||
Optional properties:
|
||||
- clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000
|
||||
- Child nodes conforming to i2c bus binding
|
||||
|
||||
Examples:
|
||||
I2C0@f8b10000 {
|
||||
compatible = "hisilicon,hix5hd2-i2c";
|
||||
reg = <0xf8b10000 0x1000>;
|
||||
interrupts = <0 38 4>;
|
||||
clocks = <&clock HIX5HD2_I2C0_RST>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
}
|
||||
@@ -10,9 +10,11 @@ maintainers:
|
||||
- Chris Packham <chris.packham@alliedtelesis.co.nz>
|
||||
|
||||
description:
|
||||
The RTL9300 SoC has two I2C controllers. Each of these has an SCL line (which
|
||||
RTL9300 SoCs have two I2C controllers. Each of these has an SCL line (which
|
||||
if not-used for SCL can be a GPIO). There are 8 common SDA lines that can be
|
||||
assigned to either I2C controller.
|
||||
RTL9310 SoCs have equal capabilities but support 12 common SDA lines which
|
||||
can be assigned to either I2C controller.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@@ -23,11 +25,19 @@ properties:
|
||||
- realtek,rtl9302c-i2c
|
||||
- realtek,rtl9303-i2c
|
||||
- const: realtek,rtl9301-i2c
|
||||
- const: realtek,rtl9301-i2c
|
||||
- items:
|
||||
- enum:
|
||||
- realtek,rtl9311-i2c
|
||||
- realtek,rtl9312-i2c
|
||||
- realtek,rtl9313-i2c
|
||||
- const: realtek,rtl9310-i2c
|
||||
- enum:
|
||||
- realtek,rtl9301-i2c
|
||||
- realtek,rtl9310-i2c
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: Register offset and size this I2C controller.
|
||||
- description: Register offset and size of this I2C controller.
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
@@ -35,19 +45,44 @@ properties:
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
realtek,scl:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
The SCL line number of this I2C controller.
|
||||
enum: [ 0, 1 ]
|
||||
|
||||
patternProperties:
|
||||
'^i2c@[0-7]$':
|
||||
'^i2c@[0-9ab]$':
|
||||
$ref: /schemas/i2c/i2c-controller.yaml
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: The SDA pin associated with the I2C bus.
|
||||
description: The SDA line number associated with the I2C bus.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: realtek,rtl9310-i2c
|
||||
then:
|
||||
required:
|
||||
- realtek,scl
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: realtek,rtl9301-i2c
|
||||
then:
|
||||
patternProperties:
|
||||
'^i2c@[89ab]$': false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
=================
|
||||
What is aty128fb?
|
||||
=================
|
||||
|
||||
.. [This file is cloned from VesaFB/matroxfb]
|
||||
=========================================
|
||||
aty128fb - ATI Rage128 framebuffer driver
|
||||
=========================================
|
||||
|
||||
This is a driver for a graphic framebuffer for ATI Rage128 based devices
|
||||
on Intel and PPC boxes.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
==============
|
||||
What is efifb?
|
||||
==============
|
||||
===================================
|
||||
efifb - Generic EFI platform driver
|
||||
===================================
|
||||
|
||||
This is a generic EFI platform driver for systems with UEFI firmware. The
|
||||
system must be booted via the EFI stub for this to be usable. efifb supports
|
||||
|
||||
@@ -41,7 +41,6 @@ your board initialisation function::
|
||||
|
||||
ep93xx_register_fb(&some_board_fb_info);
|
||||
|
||||
=====================
|
||||
Video Attribute Flags
|
||||
=====================
|
||||
|
||||
@@ -79,7 +78,6 @@ EP93XXFB_USE_SDCSN2 Use SDCSn[2] for the framebuffer.
|
||||
EP93XXFB_USE_SDCSN3 Use SDCSn[3] for the framebuffer.
|
||||
=============================== ======================================
|
||||
|
||||
==================
|
||||
Platform callbacks
|
||||
==================
|
||||
|
||||
@@ -101,7 +99,6 @@ obtained as follows::
|
||||
/* Board specific framebuffer setup */
|
||||
}
|
||||
|
||||
======================
|
||||
Setting the video mode
|
||||
======================
|
||||
|
||||
@@ -119,7 +116,6 @@ set when the module is installed::
|
||||
|
||||
modprobe ep93xx-fb video=320x240
|
||||
|
||||
==============
|
||||
Screenpage bug
|
||||
==============
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
=============
|
||||
What is gxfb?
|
||||
=============
|
||||
|
||||
.. [This file is cloned from VesaFB/aty128fb]
|
||||
=======================================
|
||||
gxfb - AMD Geode GX2 framebuffer driver
|
||||
=======================================
|
||||
|
||||
This is a graphics framebuffer driver for AMD Geode GX2 based processors.
|
||||
|
||||
|
||||
+45
-35
@@ -4,42 +4,52 @@
|
||||
Frame Buffer
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
General information
|
||||
===================
|
||||
|
||||
api
|
||||
arkfb
|
||||
aty128fb
|
||||
cirrusfb
|
||||
cmap_xfbdev
|
||||
deferred_io
|
||||
efifb
|
||||
ep93xx-fb
|
||||
fbcon
|
||||
framebuffer
|
||||
gxfb
|
||||
intel810
|
||||
internals
|
||||
lxfb
|
||||
matroxfb
|
||||
metronomefb
|
||||
modedb
|
||||
pvr2fb
|
||||
pxafb
|
||||
s3fb
|
||||
sa1100fb
|
||||
sh7760fb
|
||||
sisfb
|
||||
sm501
|
||||
sm712fb
|
||||
sstfb
|
||||
tgafb
|
||||
tridentfb
|
||||
udlfb
|
||||
uvesafb
|
||||
vesafb
|
||||
viafb
|
||||
vt8623fb
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
api
|
||||
cmap_xfbdev
|
||||
deferred_io
|
||||
fbcon
|
||||
framebuffer
|
||||
internals
|
||||
modedb
|
||||
|
||||
Driver documentation
|
||||
====================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
arkfb
|
||||
aty128fb
|
||||
cirrusfb
|
||||
efifb
|
||||
ep93xx-fb
|
||||
gxfb
|
||||
intel810
|
||||
lxfb
|
||||
matroxfb
|
||||
metronomefb
|
||||
pvr2fb
|
||||
pxafb
|
||||
s3fb
|
||||
sa1100fb
|
||||
sh7760fb
|
||||
sisfb
|
||||
sm501
|
||||
sm712fb
|
||||
sstfb
|
||||
tgafb
|
||||
tridentfb
|
||||
udlfb
|
||||
uvesafb
|
||||
vesafb
|
||||
viafb
|
||||
vt8623fb
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
=============
|
||||
What is lxfb?
|
||||
=============
|
||||
|
||||
.. [This file is cloned from VesaFB/aty128fb]
|
||||
|
||||
======================================
|
||||
lxfb - AMD Geode LX framebuffer driver
|
||||
======================================
|
||||
|
||||
This is a graphics framebuffer driver for AMD Geode LX based processors.
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
=================
|
||||
What is matroxfb?
|
||||
=================
|
||||
|
||||
.. [This file is cloned from VesaFB. Thanks go to Gerd Knorr]
|
||||
|
||||
================================================
|
||||
matroxfb - Framebuffer driver for Matrox devices
|
||||
================================================
|
||||
|
||||
This is a driver for a graphic framebuffer for Matrox devices on
|
||||
Alpha, Intel and PPC boxes.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
===============
|
||||
What is pvr2fb?
|
||||
===============
|
||||
===============================================
|
||||
pvr2fb - PowerVR 2 graphics frame buffer driver
|
||||
===============================================
|
||||
|
||||
This is a driver for PowerVR 2 based graphics frame buffers, such as the
|
||||
one found in the Dreamcast.
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
=================
|
||||
What is sa1100fb?
|
||||
=================
|
||||
|
||||
.. [This file is cloned from VesaFB/matroxfb]
|
||||
|
||||
=================================================
|
||||
sa1100fb - SA-1100 LCD graphic framebuffer driver
|
||||
=================================================
|
||||
|
||||
This is a driver for a graphic framebuffer for the SA-1100 LCD
|
||||
controller.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
==============
|
||||
What is sisfb?
|
||||
==============
|
||||
=====================================
|
||||
sisfb - SiS framebuffer device driver
|
||||
=====================================
|
||||
|
||||
sisfb is a framebuffer device driver for SiS (Silicon Integrated Systems)
|
||||
graphics chips. Supported are:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
================
|
||||
What is sm712fb?
|
||||
================
|
||||
==========================================================
|
||||
sm712fb - Silicon Motion SM712 graphics framebuffer driver
|
||||
==========================================================
|
||||
|
||||
This is a graphics framebuffer driver for Silicon Motion SM712 based processors.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
==============
|
||||
What is tgafb?
|
||||
==============
|
||||
=======================================
|
||||
tgafb - TGA graphics framebuffer driver
|
||||
=======================================
|
||||
|
||||
This is a driver for DECChip 21030 based graphics framebuffers, a.k.a. TGA
|
||||
cards, which are usually found in older Digital Alpha systems. The
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
==============
|
||||
What is udlfb?
|
||||
==============
|
||||
==================================
|
||||
udlfb - DisplayLink USB 2.0 driver
|
||||
==================================
|
||||
|
||||
This is a driver for DisplayLink USB 2.0 era graphics chips.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
===============
|
||||
What is vesafb?
|
||||
===============
|
||||
===========================================
|
||||
vesafb - Generic graphic framebuffer driver
|
||||
===========================================
|
||||
|
||||
This is a generic driver for a graphic framebuffer on intel boxes.
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ FX-bus
|
||||
|
||||
name='Clock Source',index=0
|
||||
---------------------------
|
||||
This control allows switching the word clock between interally generated
|
||||
This control allows switching the word clock between internally generated
|
||||
44.1 or 48 kHz, or a number of external sources.
|
||||
|
||||
Note: the sources for the 1616 CardBus card are unclear. Please report your
|
||||
|
||||
@@ -18345,6 +18345,7 @@ F: Documentation/core-api/symbol-namespaces.rst
|
||||
F: scripts/nsdeps
|
||||
|
||||
NTB AMD DRIVER
|
||||
M: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
|
||||
M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
|
||||
L: ntb@lists.linux.dev
|
||||
S: Supported
|
||||
|
||||
@@ -31,6 +31,9 @@ config PARISC
|
||||
select HAVE_KERNEL_UNCOMPRESSED
|
||||
select HAVE_PCI
|
||||
select HAVE_PERF_EVENTS
|
||||
select HAVE_PERF_REGS
|
||||
select HAVE_PERF_USER_STACK_DUMP
|
||||
select PERF_USE_VMALLOC
|
||||
select HAVE_KERNEL_BZIP2
|
||||
select HAVE_KERNEL_GZIP
|
||||
select HAVE_KERNEL_LZ4
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
#ifndef __ASM_PARISC_PERF_EVENT_H
|
||||
#define __ASM_PARISC_PERF_EVENT_H
|
||||
|
||||
/* Empty, just to avoid compiling error */
|
||||
#include <asm/psw.h>
|
||||
|
||||
#define perf_arch_fetch_caller_regs(regs, __ip) { \
|
||||
(regs)->gr[0] = KERNEL_PSW; \
|
||||
(regs)->iaoq[0] = (__ip); \
|
||||
asm volatile("copy %%sp, %0\n":"=r"((regs)->gr[30])); \
|
||||
}
|
||||
|
||||
#endif /* __ASM_PARISC_PERF_EVENT_H */
|
||||
@@ -10,10 +10,10 @@
|
||||
#define TCSETS _IOW('T', 17, struct termios) /* TCSETATTR */
|
||||
#define TCSETSW _IOW('T', 18, struct termios) /* TCSETATTRD */
|
||||
#define TCSETSF _IOW('T', 19, struct termios) /* TCSETATTRF */
|
||||
#define TCGETA _IOR('T', 1, struct termio)
|
||||
#define TCSETA _IOW('T', 2, struct termio)
|
||||
#define TCSETAW _IOW('T', 3, struct termio)
|
||||
#define TCSETAF _IOW('T', 4, struct termio)
|
||||
#define TCGETA 0x40125401
|
||||
#define TCSETA 0x80125402
|
||||
#define TCSETAW 0x80125403
|
||||
#define TCSETAF 0x80125404
|
||||
#define TCSBRK _IO('T', 5)
|
||||
#define TCXONC _IO('T', 6)
|
||||
#define TCFLSH _IO('T', 7)
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef _UAPI_ASM_PARISC_PERF_REGS_H
|
||||
#define _UAPI_ASM_PARISC_PERF_REGS_H
|
||||
|
||||
/* see struct user_regs_struct */
|
||||
enum perf_event_parisc_regs {
|
||||
PERF_REG_PARISC_R0, /* PSW is in gr[0] */
|
||||
PERF_REG_PARISC_R1,
|
||||
PERF_REG_PARISC_R2,
|
||||
PERF_REG_PARISC_R3,
|
||||
PERF_REG_PARISC_R4,
|
||||
PERF_REG_PARISC_R5,
|
||||
PERF_REG_PARISC_R6,
|
||||
PERF_REG_PARISC_R7,
|
||||
PERF_REG_PARISC_R8,
|
||||
PERF_REG_PARISC_R9,
|
||||
PERF_REG_PARISC_R10,
|
||||
PERF_REG_PARISC_R11,
|
||||
PERF_REG_PARISC_R12,
|
||||
PERF_REG_PARISC_R13,
|
||||
PERF_REG_PARISC_R14,
|
||||
PERF_REG_PARISC_R15,
|
||||
PERF_REG_PARISC_R16,
|
||||
PERF_REG_PARISC_R17,
|
||||
PERF_REG_PARISC_R18,
|
||||
PERF_REG_PARISC_R19,
|
||||
PERF_REG_PARISC_R20,
|
||||
PERF_REG_PARISC_R21,
|
||||
PERF_REG_PARISC_R22,
|
||||
PERF_REG_PARISC_R23,
|
||||
PERF_REG_PARISC_R24,
|
||||
PERF_REG_PARISC_R25,
|
||||
PERF_REG_PARISC_R26,
|
||||
PERF_REG_PARISC_R27,
|
||||
PERF_REG_PARISC_R28,
|
||||
PERF_REG_PARISC_R29,
|
||||
PERF_REG_PARISC_R30,
|
||||
PERF_REG_PARISC_R31,
|
||||
|
||||
PERF_REG_PARISC_SR0,
|
||||
PERF_REG_PARISC_SR1,
|
||||
PERF_REG_PARISC_SR2,
|
||||
PERF_REG_PARISC_SR3,
|
||||
PERF_REG_PARISC_SR4,
|
||||
PERF_REG_PARISC_SR5,
|
||||
PERF_REG_PARISC_SR6,
|
||||
PERF_REG_PARISC_SR7,
|
||||
|
||||
PERF_REG_PARISC_IAOQ0,
|
||||
PERF_REG_PARISC_IAOQ1,
|
||||
PERF_REG_PARISC_IASQ0,
|
||||
PERF_REG_PARISC_IASQ1,
|
||||
|
||||
PERF_REG_PARISC_SAR, /* CR11 */
|
||||
PERF_REG_PARISC_IIR, /* CR19 */
|
||||
PERF_REG_PARISC_ISR, /* CR20 */
|
||||
PERF_REG_PARISC_IOR, /* CR21 */
|
||||
PERF_REG_PARISC_IPSW, /* CR22 */
|
||||
|
||||
PERF_REG_PARISC_MAX
|
||||
};
|
||||
|
||||
#endif /* _UAPI_ASM_PARISC_PERF_REGS_H */
|
||||
@@ -38,6 +38,7 @@ obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += topology.o
|
||||
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o
|
||||
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
|
||||
obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_regs.o
|
||||
obj-$(CONFIG_KGDB) += kgdb.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o
|
||||
obj-$(CONFIG_KEXEC_CORE) += kexec.o relocate_kernel.o
|
||||
|
||||
@@ -995,6 +995,7 @@ static __init int qemu_print_iodc_data(struct device *lin_dev, void *data)
|
||||
struct pdc_system_map_mod_info pdc_mod_info;
|
||||
struct pdc_module_path mod_path;
|
||||
|
||||
memset(&iodc_data, 0, sizeof(iodc_data));
|
||||
status = pdc_iodc_read(&count, hpa, 0,
|
||||
&iodc_data, sizeof(iodc_data));
|
||||
if (status != PDC_OK) {
|
||||
@@ -1012,6 +1013,11 @@ static __init int qemu_print_iodc_data(struct device *lin_dev, void *data)
|
||||
|
||||
mod_index = 0;
|
||||
do {
|
||||
/* initialize device path for old machines */
|
||||
memset(&mod_path, 0xff, sizeof(mod_path));
|
||||
get_node_path(dev->dev.parent, &mod_path.path);
|
||||
mod_path.path.mod = dev->hw_path;
|
||||
memset(&pdc_mod_info, 0, sizeof(pdc_mod_info));
|
||||
status = pdc_system_map_find_mods(&pdc_mod_info,
|
||||
&mod_path, mod_index++);
|
||||
} while (status == PDC_OK && pdc_mod_info.mod_addr != hpa);
|
||||
|
||||
@@ -464,7 +464,8 @@ int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info,
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pdc_lock, flags);
|
||||
retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, __pa(pdc_result),
|
||||
memcpy(pdc_result2, mod_path, sizeof(*mod_path));
|
||||
retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, __pa(pdc_result),
|
||||
__pa(pdc_result2), mod_index);
|
||||
convert_to_wide(pdc_result);
|
||||
memcpy(pdc_mod_info, pdc_result, sizeof(*pdc_mod_info));
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Performance event support for parisc
|
||||
*
|
||||
* Copyright (C) 2025 by Helge Deller <deller@gmx.de>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <asm/unwind.h>
|
||||
|
||||
void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
|
||||
struct unwind_frame_info info;
|
||||
|
||||
unwind_frame_init_task(&info, current, NULL);
|
||||
while (1) {
|
||||
if (unwind_once(&info) < 0 || info.ip == 0)
|
||||
break;
|
||||
|
||||
if (!__kernel_text_address(info.ip) ||
|
||||
perf_callchain_store(entry, info.ip))
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/* Copyright (C) 2025 by Helge Deller <deller@gmx.de> */
|
||||
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/perf_regs.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
u64 perf_reg_value(struct pt_regs *regs, int idx)
|
||||
{
|
||||
switch (idx) {
|
||||
case PERF_REG_PARISC_R0 ... PERF_REG_PARISC_R31:
|
||||
return regs->gr[idx - PERF_REG_PARISC_R0];
|
||||
case PERF_REG_PARISC_SR0 ... PERF_REG_PARISC_SR7:
|
||||
return regs->sr[idx - PERF_REG_PARISC_SR0];
|
||||
case PERF_REG_PARISC_IASQ0 ... PERF_REG_PARISC_IASQ1:
|
||||
return regs->iasq[idx - PERF_REG_PARISC_IASQ0];
|
||||
case PERF_REG_PARISC_IAOQ0 ... PERF_REG_PARISC_IAOQ1:
|
||||
return regs->iasq[idx - PERF_REG_PARISC_IAOQ0];
|
||||
case PERF_REG_PARISC_SAR: /* CR11 */
|
||||
return regs->sar;
|
||||
case PERF_REG_PARISC_IIR: /* CR19 */
|
||||
return regs->iir;
|
||||
case PERF_REG_PARISC_ISR: /* CR20 */
|
||||
return regs->isr;
|
||||
case PERF_REG_PARISC_IOR: /* CR21 */
|
||||
return regs->ior;
|
||||
case PERF_REG_PARISC_IPSW: /* CR22 */
|
||||
return regs->ipsw;
|
||||
};
|
||||
WARN_ON_ONCE((u32)idx >= PERF_REG_PARISC_MAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define REG_RESERVED (~((1ULL << PERF_REG_PARISC_MAX) - 1))
|
||||
|
||||
int perf_reg_validate(u64 mask)
|
||||
{
|
||||
if (!mask || mask & REG_RESERVED)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 perf_reg_abi(struct task_struct *task)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_64BIT))
|
||||
return PERF_SAMPLE_REGS_ABI_32;
|
||||
|
||||
if (test_tsk_thread_flag(task, TIF_32BIT))
|
||||
return PERF_SAMPLE_REGS_ABI_32;
|
||||
|
||||
return PERF_SAMPLE_REGS_ABI_64;
|
||||
}
|
||||
|
||||
void perf_get_regs_user(struct perf_regs *regs_user,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
regs_user->regs = task_pt_regs(current);
|
||||
regs_user->abi = perf_reg_abi(current);
|
||||
}
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/kfence.h>
|
||||
#include <linux/perf_event.h>
|
||||
|
||||
#include <asm/assembly.h>
|
||||
#include <asm/io.h>
|
||||
@@ -633,6 +634,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
|
||||
/* Assist Exception Trap, i.e. floating point exception. */
|
||||
die_if_kernel("Floating point exception", regs, 0); /* quiet */
|
||||
__inc_irq_stat(irq_fpassist_count);
|
||||
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
|
||||
handle_fpe(regs);
|
||||
return;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <asm/hardirq.h>
|
||||
#include <asm/traps.h>
|
||||
#include "unaligned.h"
|
||||
@@ -378,6 +379,7 @@ void handle_unaligned(struct pt_regs *regs)
|
||||
int ret = ERR_NOTHANDLED;
|
||||
|
||||
__inc_irq_stat(irq_unaligned_count);
|
||||
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, regs->ior);
|
||||
|
||||
/* log a message with pacing */
|
||||
if (user_mode(regs)) {
|
||||
|
||||
@@ -41,7 +41,6 @@ unsigned long raw_copy_from_user(void *dst, const void __user *src,
|
||||
mtsp(get_kernel_space(), SR_TEMP2);
|
||||
|
||||
/* Check region is user accessible */
|
||||
if (start)
|
||||
while (start < end) {
|
||||
if (!prober_user(SR_TEMP1, start)) {
|
||||
newlen = (start - (unsigned long) src);
|
||||
|
||||
+2
-3
@@ -1319,7 +1319,7 @@ static int bio_iov_iter_align_down(struct bio *bio, struct iov_iter *iter,
|
||||
}
|
||||
|
||||
/**
|
||||
* bio_iov_iter_get_pages_aligned - add user or kernel pages to a bio
|
||||
* bio_iov_iter_get_pages - add user or kernel pages to a bio
|
||||
* @bio: bio to add pages to
|
||||
* @iter: iov iterator describing the region to be added
|
||||
* @len_align_mask: the mask to align the total size to, 0 for any length
|
||||
@@ -1339,7 +1339,7 @@ static int bio_iov_iter_align_down(struct bio *bio, struct iov_iter *iter,
|
||||
* MM encounters an error pinning the requested pages, it stops. Error
|
||||
* is returned only if 0 pages could be pinned.
|
||||
*/
|
||||
int bio_iov_iter_get_pages_aligned(struct bio *bio, struct iov_iter *iter,
|
||||
int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter,
|
||||
unsigned len_align_mask)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -1363,7 +1363,6 @@ int bio_iov_iter_get_pages_aligned(struct bio *bio, struct iov_iter *iter,
|
||||
return bio_iov_iter_align_down(bio, iter, len_align_mask);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bio_iov_iter_get_pages_aligned);
|
||||
|
||||
static void submit_bio_wait_endio(struct bio *bio)
|
||||
{
|
||||
|
||||
+5
-1
@@ -283,7 +283,11 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
|
||||
bio = blk_rq_map_bio_alloc(rq, nr_vecs, gfp_mask);
|
||||
if (!bio)
|
||||
return -ENOMEM;
|
||||
ret = bio_iov_iter_get_pages(bio, iter);
|
||||
/*
|
||||
* No alignment requirements on our part to support arbitrary
|
||||
* passthrough commands.
|
||||
*/
|
||||
ret = bio_iov_iter_get_pages(bio, iter, 0);
|
||||
if (ret)
|
||||
goto out_put;
|
||||
ret = blk_rq_append_bio(rq, bio);
|
||||
|
||||
+10
-3
@@ -43,6 +43,13 @@ static bool blkdev_dio_invalid(struct block_device *bdev, struct kiocb *iocb,
|
||||
(bdev_logical_block_size(bdev) - 1);
|
||||
}
|
||||
|
||||
static inline int blkdev_iov_iter_get_pages(struct bio *bio,
|
||||
struct iov_iter *iter, struct block_device *bdev)
|
||||
{
|
||||
return bio_iov_iter_get_pages(bio, iter,
|
||||
bdev_logical_block_size(bdev) - 1);
|
||||
}
|
||||
|
||||
#define DIO_INLINE_BIO_VECS 4
|
||||
|
||||
static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,
|
||||
@@ -78,7 +85,7 @@ static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,
|
||||
if (iocb->ki_flags & IOCB_ATOMIC)
|
||||
bio.bi_opf |= REQ_ATOMIC;
|
||||
|
||||
ret = bio_iov_iter_get_bdev_pages(&bio, iter, bdev);
|
||||
ret = blkdev_iov_iter_get_pages(&bio, iter, bdev);
|
||||
if (unlikely(ret))
|
||||
goto out;
|
||||
ret = bio.bi_iter.bi_size;
|
||||
@@ -212,7 +219,7 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
|
||||
bio->bi_end_io = blkdev_bio_end_io;
|
||||
bio->bi_ioprio = iocb->ki_ioprio;
|
||||
|
||||
ret = bio_iov_iter_get_bdev_pages(bio, iter, bdev);
|
||||
ret = blkdev_iov_iter_get_pages(bio, iter, bdev);
|
||||
if (unlikely(ret)) {
|
||||
bio->bi_status = BLK_STS_IOERR;
|
||||
bio_endio(bio);
|
||||
@@ -348,7 +355,7 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
|
||||
*/
|
||||
bio_iov_bvec_set(bio, iter);
|
||||
} else {
|
||||
ret = bio_iov_iter_get_bdev_pages(bio, iter, bdev);
|
||||
ret = blkdev_iov_iter_get_pages(bio, iter, bdev);
|
||||
if (unlikely(ret))
|
||||
goto out_bio_put;
|
||||
}
|
||||
|
||||
+6
-8
@@ -186,9 +186,14 @@ static int essiv_aead_crypt(struct aead_request *req, bool enc)
|
||||
const struct essiv_tfm_ctx *tctx = crypto_aead_ctx(tfm);
|
||||
struct essiv_aead_request_ctx *rctx = aead_request_ctx(req);
|
||||
struct aead_request *subreq = &rctx->aead_req;
|
||||
int ivsize = crypto_aead_ivsize(tfm);
|
||||
int ssize = req->assoclen - ivsize;
|
||||
struct scatterlist *src = req->src;
|
||||
int err;
|
||||
|
||||
if (ssize < 0)
|
||||
return -EINVAL;
|
||||
|
||||
crypto_cipher_encrypt_one(tctx->essiv_cipher, req->iv, req->iv);
|
||||
|
||||
/*
|
||||
@@ -198,19 +203,12 @@ static int essiv_aead_crypt(struct aead_request *req, bool enc)
|
||||
*/
|
||||
rctx->assoc = NULL;
|
||||
if (req->src == req->dst || !enc) {
|
||||
scatterwalk_map_and_copy(req->iv, req->dst,
|
||||
req->assoclen - crypto_aead_ivsize(tfm),
|
||||
crypto_aead_ivsize(tfm), 1);
|
||||
scatterwalk_map_and_copy(req->iv, req->dst, ssize, ivsize, 1);
|
||||
} else {
|
||||
u8 *iv = (u8 *)aead_request_ctx(req) + tctx->ivoffset;
|
||||
int ivsize = crypto_aead_ivsize(tfm);
|
||||
int ssize = req->assoclen - ivsize;
|
||||
struct scatterlist *sg;
|
||||
int nents;
|
||||
|
||||
if (ssize < 0)
|
||||
return -EINVAL;
|
||||
|
||||
nents = sg_nents_for_len(req->src, ssize);
|
||||
if (nents < 0)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -294,6 +294,8 @@ static int crypto_skcipher_init_tfm(struct crypto_tfm *tfm)
|
||||
return crypto_init_lskcipher_ops_sg(tfm);
|
||||
}
|
||||
|
||||
crypto_skcipher_set_reqsize(skcipher, crypto_tfm_alg_reqsize(tfm));
|
||||
|
||||
if (alg->exit)
|
||||
skcipher->base.exit = crypto_skcipher_exit_tfm;
|
||||
|
||||
|
||||
@@ -542,8 +542,10 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
|
||||
return -EBADF;
|
||||
|
||||
error = loop_check_backing_file(file);
|
||||
if (error)
|
||||
if (error) {
|
||||
fput(file);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* suppress uevents while reconfiguring the device */
|
||||
dev_set_uevent_suppress(disk_to_dev(lo->lo_disk), 1);
|
||||
@@ -813,7 +815,7 @@ static void loop_queue_work(struct loop_device *lo, struct loop_cmd *cmd)
|
||||
if (worker)
|
||||
goto queue_work;
|
||||
|
||||
worker = kzalloc(sizeof(struct loop_worker), GFP_NOWAIT | __GFP_NOWARN);
|
||||
worker = kzalloc(sizeof(struct loop_worker), GFP_NOWAIT);
|
||||
/*
|
||||
* In the event we cannot allocate a worker, just queue on the
|
||||
* rootcg worker and issue the I/O as the rootcg
|
||||
@@ -985,8 +987,10 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode,
|
||||
return -EBADF;
|
||||
|
||||
error = loop_check_backing_file(file);
|
||||
if (error)
|
||||
if (error) {
|
||||
fput(file);
|
||||
return error;
|
||||
}
|
||||
|
||||
is_loop = is_loop_device(file);
|
||||
|
||||
|
||||
@@ -29,10 +29,11 @@ if TCG_TPM
|
||||
|
||||
config TCG_TPM2_HMAC
|
||||
bool "Use HMAC and encrypted transactions on the TPM bus"
|
||||
default X86_64
|
||||
default n
|
||||
select CRYPTO_ECDH
|
||||
select CRYPTO_LIB_AESCFB
|
||||
select CRYPTO_LIB_SHA256
|
||||
select CRYPTO_LIB_UTILS
|
||||
help
|
||||
Setting this causes us to deploy a scheme which uses request
|
||||
and response HMACs in addition to encryption for
|
||||
|
||||
@@ -52,7 +52,7 @@ MODULE_PARM_DESC(suspend_pcr,
|
||||
unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
|
||||
{
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
return tpm2_calc_ordinal_duration(chip, ordinal);
|
||||
return tpm2_calc_ordinal_duration(ordinal);
|
||||
else
|
||||
return tpm1_calc_ordinal_duration(chip, ordinal);
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
|
||||
ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip);
|
||||
int tpm2_auto_startup(struct tpm_chip *chip);
|
||||
void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
|
||||
unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
|
||||
unsigned long tpm2_calc_ordinal_duration(u32 ordinal);
|
||||
int tpm2_probe(struct tpm_chip *chip);
|
||||
int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip);
|
||||
int tpm2_find_cc(struct tpm_chip *chip, u32 cc);
|
||||
|
||||
+32
-95
@@ -28,120 +28,57 @@ static struct tpm2_hash tpm2_hash_map[] = {
|
||||
|
||||
int tpm2_get_timeouts(struct tpm_chip *chip)
|
||||
{
|
||||
/* Fixed timeouts for TPM2 */
|
||||
chip->timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
|
||||
chip->timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
|
||||
chip->timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
|
||||
chip->timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
|
||||
|
||||
/* PTP spec timeouts */
|
||||
chip->duration[TPM_SHORT] = msecs_to_jiffies(TPM2_DURATION_SHORT);
|
||||
chip->duration[TPM_MEDIUM] = msecs_to_jiffies(TPM2_DURATION_MEDIUM);
|
||||
chip->duration[TPM_LONG] = msecs_to_jiffies(TPM2_DURATION_LONG);
|
||||
|
||||
/* Key creation commands long timeouts */
|
||||
chip->duration[TPM_LONG_LONG] =
|
||||
msecs_to_jiffies(TPM2_DURATION_LONG_LONG);
|
||||
|
||||
chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm2_ordinal_duration_index() - returns an index to the chip duration table
|
||||
* @ordinal: TPM command ordinal.
|
||||
*
|
||||
* The function returns an index to the chip duration table
|
||||
* (enum tpm_duration), that describes the maximum amount of
|
||||
* time the chip could take to return the result for a particular ordinal.
|
||||
*
|
||||
* The values of the MEDIUM, and LONG durations are taken
|
||||
* from the PC Client Profile (PTP) specification (750, 2000 msec)
|
||||
*
|
||||
* LONG_LONG is for commands that generates keys which empirically takes
|
||||
* a longer time on some systems.
|
||||
*
|
||||
* Return:
|
||||
* * TPM_MEDIUM
|
||||
* * TPM_LONG
|
||||
* * TPM_LONG_LONG
|
||||
* * TPM_UNDEFINED
|
||||
/*
|
||||
* Contains the maximum durations in milliseconds for TPM2 commands.
|
||||
*/
|
||||
static u8 tpm2_ordinal_duration_index(u32 ordinal)
|
||||
{
|
||||
switch (ordinal) {
|
||||
/* Startup */
|
||||
case TPM2_CC_STARTUP: /* 144 */
|
||||
return TPM_MEDIUM;
|
||||
|
||||
case TPM2_CC_SELF_TEST: /* 143 */
|
||||
return TPM_LONG;
|
||||
|
||||
case TPM2_CC_GET_RANDOM: /* 17B */
|
||||
return TPM_LONG;
|
||||
|
||||
case TPM2_CC_SEQUENCE_UPDATE: /* 15C */
|
||||
return TPM_MEDIUM;
|
||||
case TPM2_CC_SEQUENCE_COMPLETE: /* 13E */
|
||||
return TPM_MEDIUM;
|
||||
case TPM2_CC_EVENT_SEQUENCE_COMPLETE: /* 185 */
|
||||
return TPM_MEDIUM;
|
||||
case TPM2_CC_HASH_SEQUENCE_START: /* 186 */
|
||||
return TPM_MEDIUM;
|
||||
|
||||
case TPM2_CC_VERIFY_SIGNATURE: /* 177 */
|
||||
return TPM_LONG_LONG;
|
||||
|
||||
case TPM2_CC_PCR_EXTEND: /* 182 */
|
||||
return TPM_MEDIUM;
|
||||
|
||||
case TPM2_CC_HIERARCHY_CONTROL: /* 121 */
|
||||
return TPM_LONG;
|
||||
case TPM2_CC_HIERARCHY_CHANGE_AUTH: /* 129 */
|
||||
return TPM_LONG;
|
||||
|
||||
case TPM2_CC_GET_CAPABILITY: /* 17A */
|
||||
return TPM_MEDIUM;
|
||||
|
||||
case TPM2_CC_NV_READ: /* 14E */
|
||||
return TPM_LONG;
|
||||
|
||||
case TPM2_CC_CREATE_PRIMARY: /* 131 */
|
||||
return TPM_LONG_LONG;
|
||||
case TPM2_CC_CREATE: /* 153 */
|
||||
return TPM_LONG_LONG;
|
||||
case TPM2_CC_CREATE_LOADED: /* 191 */
|
||||
return TPM_LONG_LONG;
|
||||
|
||||
default:
|
||||
return TPM_UNDEFINED;
|
||||
}
|
||||
}
|
||||
static const struct {
|
||||
unsigned long ordinal;
|
||||
unsigned long duration;
|
||||
} tpm2_ordinal_duration_map[] = {
|
||||
{TPM2_CC_STARTUP, 750},
|
||||
{TPM2_CC_SELF_TEST, 3000},
|
||||
{TPM2_CC_GET_RANDOM, 2000},
|
||||
{TPM2_CC_SEQUENCE_UPDATE, 750},
|
||||
{TPM2_CC_SEQUENCE_COMPLETE, 750},
|
||||
{TPM2_CC_EVENT_SEQUENCE_COMPLETE, 750},
|
||||
{TPM2_CC_HASH_SEQUENCE_START, 750},
|
||||
{TPM2_CC_VERIFY_SIGNATURE, 30000},
|
||||
{TPM2_CC_PCR_EXTEND, 750},
|
||||
{TPM2_CC_HIERARCHY_CONTROL, 2000},
|
||||
{TPM2_CC_HIERARCHY_CHANGE_AUTH, 2000},
|
||||
{TPM2_CC_GET_CAPABILITY, 750},
|
||||
{TPM2_CC_NV_READ, 2000},
|
||||
{TPM2_CC_CREATE_PRIMARY, 30000},
|
||||
{TPM2_CC_CREATE, 30000},
|
||||
{TPM2_CC_CREATE_LOADED, 30000},
|
||||
};
|
||||
|
||||
/**
|
||||
* tpm2_calc_ordinal_duration() - calculate the maximum command duration
|
||||
* @chip: TPM chip to use.
|
||||
* tpm2_calc_ordinal_duration() - Calculate the maximum command duration
|
||||
* @ordinal: TPM command ordinal.
|
||||
*
|
||||
* The function returns the maximum amount of time the chip could take
|
||||
* to return the result for a particular ordinal in jiffies.
|
||||
*
|
||||
* Return: A maximal duration time for an ordinal in jiffies.
|
||||
* Returns the maximum amount of time the chip is expected by kernel to
|
||||
* take in jiffies.
|
||||
*/
|
||||
unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
|
||||
unsigned long tpm2_calc_ordinal_duration(u32 ordinal)
|
||||
{
|
||||
unsigned int index;
|
||||
int i;
|
||||
|
||||
index = tpm2_ordinal_duration_index(ordinal);
|
||||
for (i = 0; i < ARRAY_SIZE(tpm2_ordinal_duration_map); i++)
|
||||
if (ordinal == tpm2_ordinal_duration_map[i].ordinal)
|
||||
return msecs_to_jiffies(tpm2_ordinal_duration_map[i].duration);
|
||||
|
||||
if (index != TPM_UNDEFINED)
|
||||
return chip->duration[index];
|
||||
else
|
||||
return msecs_to_jiffies(TPM2_DURATION_DEFAULT);
|
||||
return msecs_to_jiffies(TPM2_DURATION_DEFAULT);
|
||||
}
|
||||
|
||||
|
||||
struct tpm2_pcr_read_out {
|
||||
__be32 update_cnt;
|
||||
__be32 pcr_selects_cnt;
|
||||
|
||||
@@ -69,8 +69,8 @@
|
||||
#include <linux/unaligned.h>
|
||||
#include <crypto/kpp.h>
|
||||
#include <crypto/ecdh.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/hmac.h>
|
||||
#include <crypto/sha2.h>
|
||||
#include <crypto/utils.h>
|
||||
|
||||
/* maximum number of names the TPM must remember for authorization */
|
||||
#define AUTH_MAX_NAMES 3
|
||||
@@ -384,51 +384,6 @@ EXPORT_SYMBOL_GPL(tpm_buf_append_hmac_session);
|
||||
static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
|
||||
u32 *handle, u8 *name);
|
||||
|
||||
/*
|
||||
* It turns out the crypto hmac(sha256) is hard for us to consume
|
||||
* because it assumes a fixed key and the TPM seems to change the key
|
||||
* on every operation, so we weld the hmac init and final functions in
|
||||
* here to give it the same usage characteristics as a regular hash
|
||||
*/
|
||||
static void tpm2_hmac_init(struct sha256_ctx *sctx, u8 *key, u32 key_len)
|
||||
{
|
||||
u8 pad[SHA256_BLOCK_SIZE];
|
||||
int i;
|
||||
|
||||
sha256_init(sctx);
|
||||
for (i = 0; i < sizeof(pad); i++) {
|
||||
if (i < key_len)
|
||||
pad[i] = key[i];
|
||||
else
|
||||
pad[i] = 0;
|
||||
pad[i] ^= HMAC_IPAD_VALUE;
|
||||
}
|
||||
sha256_update(sctx, pad, sizeof(pad));
|
||||
}
|
||||
|
||||
static void tpm2_hmac_final(struct sha256_ctx *sctx, u8 *key, u32 key_len,
|
||||
u8 *out)
|
||||
{
|
||||
u8 pad[SHA256_BLOCK_SIZE];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(pad); i++) {
|
||||
if (i < key_len)
|
||||
pad[i] = key[i];
|
||||
else
|
||||
pad[i] = 0;
|
||||
pad[i] ^= HMAC_OPAD_VALUE;
|
||||
}
|
||||
|
||||
/* collect the final hash; use out as temporary storage */
|
||||
sha256_final(sctx, out);
|
||||
|
||||
sha256_init(sctx);
|
||||
sha256_update(sctx, pad, sizeof(pad));
|
||||
sha256_update(sctx, out, SHA256_DIGEST_SIZE);
|
||||
sha256_final(sctx, out);
|
||||
}
|
||||
|
||||
/*
|
||||
* assume hash sha256 and nonces u, v of size SHA256_DIGEST_SIZE but
|
||||
* otherwise standard tpm2_KDFa. Note output is in bytes not bits.
|
||||
@@ -440,16 +395,16 @@ static void tpm2_KDFa(u8 *key, u32 key_len, const char *label, u8 *u,
|
||||
const __be32 bits = cpu_to_be32(bytes * 8);
|
||||
|
||||
while (bytes > 0) {
|
||||
struct sha256_ctx sctx;
|
||||
struct hmac_sha256_ctx hctx;
|
||||
__be32 c = cpu_to_be32(counter);
|
||||
|
||||
tpm2_hmac_init(&sctx, key, key_len);
|
||||
sha256_update(&sctx, (u8 *)&c, sizeof(c));
|
||||
sha256_update(&sctx, label, strlen(label)+1);
|
||||
sha256_update(&sctx, u, SHA256_DIGEST_SIZE);
|
||||
sha256_update(&sctx, v, SHA256_DIGEST_SIZE);
|
||||
sha256_update(&sctx, (u8 *)&bits, sizeof(bits));
|
||||
tpm2_hmac_final(&sctx, key, key_len, out);
|
||||
hmac_sha256_init_usingrawkey(&hctx, key, key_len);
|
||||
hmac_sha256_update(&hctx, (u8 *)&c, sizeof(c));
|
||||
hmac_sha256_update(&hctx, label, strlen(label) + 1);
|
||||
hmac_sha256_update(&hctx, u, SHA256_DIGEST_SIZE);
|
||||
hmac_sha256_update(&hctx, v, SHA256_DIGEST_SIZE);
|
||||
hmac_sha256_update(&hctx, (u8 *)&bits, sizeof(bits));
|
||||
hmac_sha256_final(&hctx, out);
|
||||
|
||||
bytes -= SHA256_DIGEST_SIZE;
|
||||
counter++;
|
||||
@@ -593,6 +548,7 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
|
||||
u32 attrs;
|
||||
u8 cphash[SHA256_DIGEST_SIZE];
|
||||
struct sha256_ctx sctx;
|
||||
struct hmac_sha256_ctx hctx;
|
||||
|
||||
if (!auth)
|
||||
return;
|
||||
@@ -704,14 +660,14 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
|
||||
sha256_final(&sctx, cphash);
|
||||
|
||||
/* now calculate the hmac */
|
||||
tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key)
|
||||
+ auth->passphrase_len);
|
||||
sha256_update(&sctx, cphash, sizeof(cphash));
|
||||
sha256_update(&sctx, auth->our_nonce, sizeof(auth->our_nonce));
|
||||
sha256_update(&sctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
|
||||
sha256_update(&sctx, &auth->attrs, 1);
|
||||
tpm2_hmac_final(&sctx, auth->session_key, sizeof(auth->session_key)
|
||||
+ auth->passphrase_len, hmac);
|
||||
hmac_sha256_init_usingrawkey(&hctx, auth->session_key,
|
||||
sizeof(auth->session_key) +
|
||||
auth->passphrase_len);
|
||||
hmac_sha256_update(&hctx, cphash, sizeof(cphash));
|
||||
hmac_sha256_update(&hctx, auth->our_nonce, sizeof(auth->our_nonce));
|
||||
hmac_sha256_update(&hctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
|
||||
hmac_sha256_update(&hctx, &auth->attrs, 1);
|
||||
hmac_sha256_final(&hctx, hmac);
|
||||
}
|
||||
EXPORT_SYMBOL(tpm_buf_fill_hmac_session);
|
||||
|
||||
@@ -751,6 +707,7 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
|
||||
u8 rphash[SHA256_DIGEST_SIZE];
|
||||
u32 attrs, cc;
|
||||
struct sha256_ctx sctx;
|
||||
struct hmac_sha256_ctx hctx;
|
||||
u16 tag = be16_to_cpu(head->tag);
|
||||
int parm_len, len, i, handles;
|
||||
|
||||
@@ -820,21 +777,20 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
|
||||
sha256_final(&sctx, rphash);
|
||||
|
||||
/* now calculate the hmac */
|
||||
tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key)
|
||||
+ auth->passphrase_len);
|
||||
sha256_update(&sctx, rphash, sizeof(rphash));
|
||||
sha256_update(&sctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
|
||||
sha256_update(&sctx, auth->our_nonce, sizeof(auth->our_nonce));
|
||||
sha256_update(&sctx, &auth->attrs, 1);
|
||||
hmac_sha256_init_usingrawkey(&hctx, auth->session_key,
|
||||
sizeof(auth->session_key) +
|
||||
auth->passphrase_len);
|
||||
hmac_sha256_update(&hctx, rphash, sizeof(rphash));
|
||||
hmac_sha256_update(&hctx, auth->tpm_nonce, sizeof(auth->tpm_nonce));
|
||||
hmac_sha256_update(&hctx, auth->our_nonce, sizeof(auth->our_nonce));
|
||||
hmac_sha256_update(&hctx, &auth->attrs, 1);
|
||||
/* we're done with the rphash, so put our idea of the hmac there */
|
||||
tpm2_hmac_final(&sctx, auth->session_key, sizeof(auth->session_key)
|
||||
+ auth->passphrase_len, rphash);
|
||||
if (memcmp(rphash, &buf->data[offset_s], SHA256_DIGEST_SIZE) == 0) {
|
||||
rc = 0;
|
||||
} else {
|
||||
hmac_sha256_final(&hctx, rphash);
|
||||
if (crypto_memneq(rphash, &buf->data[offset_s], SHA256_DIGEST_SIZE)) {
|
||||
dev_err(&chip->dev, "TPM: HMAC check failed\n");
|
||||
goto out;
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
/* now do response decryption */
|
||||
if (auth->attrs & TPM2_SA_ENCRYPT) {
|
||||
|
||||
+66
-23
@@ -33,6 +33,20 @@ static const guid_t tpm_ppi_guid =
|
||||
GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4,
|
||||
0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53);
|
||||
|
||||
static const char * const tpm_ppi_info[] = {
|
||||
"Not implemented",
|
||||
"BIOS only",
|
||||
"Blocked for OS by system firmware",
|
||||
"User required",
|
||||
"User not required",
|
||||
};
|
||||
|
||||
/* A spinlock to protect access to the cache from concurrent reads */
|
||||
static DEFINE_MUTEX(tpm_ppi_lock);
|
||||
|
||||
static u32 ppi_operations_cache[PPI_VS_REQ_END + 1];
|
||||
static bool ppi_cache_populated;
|
||||
|
||||
static bool tpm_ppi_req_has_parameter(u64 req)
|
||||
{
|
||||
return req == 23;
|
||||
@@ -277,8 +291,7 @@ cleanup:
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
|
||||
u32 end)
|
||||
static ssize_t cache_ppi_operations(acpi_handle dev_handle, char *buf)
|
||||
{
|
||||
int i;
|
||||
u32 ret;
|
||||
@@ -286,34 +299,22 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
|
||||
union acpi_object *obj, tmp;
|
||||
union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp);
|
||||
|
||||
static char *info[] = {
|
||||
"Not implemented",
|
||||
"BIOS only",
|
||||
"Blocked for OS by BIOS",
|
||||
"User required",
|
||||
"User not required",
|
||||
};
|
||||
|
||||
if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID_1,
|
||||
1 << TPM_PPI_FN_GETOPR))
|
||||
return -EPERM;
|
||||
|
||||
tmp.integer.type = ACPI_TYPE_INTEGER;
|
||||
for (i = start; i <= end; i++) {
|
||||
for (i = 0; i <= PPI_VS_REQ_END; i++) {
|
||||
tmp.integer.value = i;
|
||||
obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
|
||||
ACPI_TYPE_INTEGER, &argv,
|
||||
TPM_PPI_REVISION_ID_1);
|
||||
if (!obj) {
|
||||
if (!obj)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
ret = obj->integer.value;
|
||||
ACPI_FREE(obj);
|
||||
}
|
||||
|
||||
if (ret > 0 && ret < ARRAY_SIZE(info))
|
||||
len += sysfs_emit_at(buf, len, "%d %d: %s\n",
|
||||
i, ret, info[ret]);
|
||||
ret = obj->integer.value;
|
||||
ppi_operations_cache[i] = ret;
|
||||
ACPI_FREE(obj);
|
||||
}
|
||||
|
||||
return len;
|
||||
@@ -324,9 +325,30 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
ssize_t len = 0;
|
||||
u32 ret;
|
||||
int i;
|
||||
|
||||
return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
|
||||
PPI_TPM_REQ_MAX);
|
||||
mutex_lock(&tpm_ppi_lock);
|
||||
if (!ppi_cache_populated) {
|
||||
len = cache_ppi_operations(chip->acpi_dev_handle, buf);
|
||||
if (len < 0) {
|
||||
mutex_unlock(&tpm_ppi_lock);
|
||||
return len;
|
||||
}
|
||||
|
||||
ppi_cache_populated = true;
|
||||
}
|
||||
|
||||
for (i = 0; i <= PPI_TPM_REQ_MAX; i++) {
|
||||
ret = ppi_operations_cache[i];
|
||||
if (ret >= 0 && ret < ARRAY_SIZE(tpm_ppi_info))
|
||||
len += sysfs_emit_at(buf, len, "%d %d: %s\n",
|
||||
i, ret, tpm_ppi_info[ret]);
|
||||
}
|
||||
mutex_unlock(&tpm_ppi_lock);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
|
||||
@@ -334,9 +356,30 @@ static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
|
||||
char *buf)
|
||||
{
|
||||
struct tpm_chip *chip = to_tpm_chip(dev);
|
||||
ssize_t len = 0;
|
||||
u32 ret;
|
||||
int i;
|
||||
|
||||
return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
|
||||
PPI_VS_REQ_END);
|
||||
mutex_lock(&tpm_ppi_lock);
|
||||
if (!ppi_cache_populated) {
|
||||
len = cache_ppi_operations(chip->acpi_dev_handle, buf);
|
||||
if (len < 0) {
|
||||
mutex_unlock(&tpm_ppi_lock);
|
||||
return len;
|
||||
}
|
||||
|
||||
ppi_cache_populated = true;
|
||||
}
|
||||
|
||||
for (i = PPI_VS_REQ_START; i <= PPI_VS_REQ_END; i++) {
|
||||
ret = ppi_operations_cache[i];
|
||||
if (ret >= 0 && ret < ARRAY_SIZE(tpm_ppi_info))
|
||||
len += sysfs_emit_at(buf, len, "%d %d: %s\n",
|
||||
i, ret, tpm_ppi_info[ret]);
|
||||
}
|
||||
mutex_unlock(&tpm_ppi_lock);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL);
|
||||
|
||||
@@ -978,8 +978,8 @@ restore_irqs:
|
||||
* will call disable_irq which undoes all of the above.
|
||||
*/
|
||||
if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) {
|
||||
tpm_tis_write8(priv, original_int_vec,
|
||||
TPM_INT_VECTOR(priv->locality));
|
||||
tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality),
|
||||
original_int_vec);
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ static const struct acpi_device_id usbio_gpio_acpi_hids[] = {
|
||||
{ "INTC1007" }, /* MTL */
|
||||
{ "INTC10B2" }, /* ARL */
|
||||
{ "INTC10B5" }, /* LNL */
|
||||
{ "INTC10D1" }, /* MTL-CVF */
|
||||
{ "INTC10E2" }, /* PTL */
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -103,7 +103,7 @@ static int wcd_gpio_probe(struct platform_device *pdev)
|
||||
chip->base = -1;
|
||||
chip->ngpio = WCD934X_NPINS;
|
||||
chip->label = dev_name(dev);
|
||||
chip->can_sleep = false;
|
||||
chip->can_sleep = true;
|
||||
|
||||
return devm_gpiochip_add_data(dev, chip, data);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ static int i2c_debug;
|
||||
#define pca_clock(adap) adap->i2c_clock
|
||||
#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
|
||||
#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
|
||||
#define pca_wait(adap) adap->wait_for_completion(adap->data)
|
||||
#define pca_wait(adap) adap->wait_for_completion_cb(adap->data)
|
||||
|
||||
static void pca_reset(struct i2c_algo_pca_data *adap)
|
||||
{
|
||||
|
||||
@@ -868,7 +868,7 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
|
||||
static void mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
|
||||
{
|
||||
unsigned int clk_src;
|
||||
unsigned int step_cnt;
|
||||
@@ -938,9 +938,6 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i2c_dump_register(struct mtk_i2c *i2c)
|
||||
@@ -1460,11 +1457,7 @@ static int mtk_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
strscpy(i2c->adap.name, I2C_DRV_NAME, sizeof(i2c->adap.name));
|
||||
|
||||
ret = mtk_i2c_set_speed(i2c, clk_get_rate(i2c->clocks[speed_clk].clk));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to set the speed.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mtk_i2c_set_speed(i2c, clk_get_rate(i2c->clocks[speed_clk].clk));
|
||||
|
||||
if (i2c->dev_comp->max_dma_support > 32) {
|
||||
ret = dma_set_mask(&pdev->dev,
|
||||
|
||||
@@ -95,7 +95,7 @@ static struct i2c_algo_pca_data pca_isa_data = {
|
||||
/* .data intentionally left NULL, not needed with ISA */
|
||||
.write_byte = pca_isa_writebyte,
|
||||
.read_byte = pca_isa_readbyte,
|
||||
.wait_for_completion = pca_isa_waitforcompletion,
|
||||
.wait_for_completion_cb = pca_isa_waitforcompletion,
|
||||
.reset_chip = pca_isa_resetchip,
|
||||
};
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ static int i2c_pca_pf_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
i2c->algo_data.data = i2c;
|
||||
i2c->algo_data.wait_for_completion = i2c_pca_pf_waitforcompletion;
|
||||
i2c->algo_data.wait_for_completion_cb = i2c_pca_pf_waitforcompletion;
|
||||
if (i2c->gpio)
|
||||
i2c->algo_data.reset_chip = i2c_pca_pf_resetchip;
|
||||
else
|
||||
|
||||
+295
-176
@@ -8,6 +8,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
enum rtl9300_bus_freq {
|
||||
RTL9300_I2C_STD_FREQ,
|
||||
@@ -20,103 +21,143 @@ struct rtl9300_i2c_chan {
|
||||
struct i2c_adapter adap;
|
||||
struct rtl9300_i2c *i2c;
|
||||
enum rtl9300_bus_freq bus_freq;
|
||||
u8 sda_pin;
|
||||
u8 sda_num;
|
||||
};
|
||||
|
||||
enum rtl9300_i2c_reg_scope {
|
||||
REG_SCOPE_GLOBAL,
|
||||
REG_SCOPE_MASTER,
|
||||
};
|
||||
|
||||
struct rtl9300_i2c_reg_field {
|
||||
struct reg_field field;
|
||||
enum rtl9300_i2c_reg_scope scope;
|
||||
};
|
||||
|
||||
enum rtl9300_i2c_reg_fields {
|
||||
F_DATA_WIDTH = 0,
|
||||
F_DEV_ADDR,
|
||||
F_I2C_FAIL,
|
||||
F_I2C_TRIG,
|
||||
F_MEM_ADDR,
|
||||
F_MEM_ADDR_WIDTH,
|
||||
F_RD_MODE,
|
||||
F_RWOP,
|
||||
F_SCL_FREQ,
|
||||
F_SCL_SEL,
|
||||
F_SDA_OUT_SEL,
|
||||
F_SDA_SEL,
|
||||
|
||||
/* keep last */
|
||||
F_NUM_FIELDS
|
||||
};
|
||||
|
||||
struct rtl9300_i2c_drv_data {
|
||||
struct rtl9300_i2c_reg_field field_desc[F_NUM_FIELDS];
|
||||
int (*select_scl)(struct rtl9300_i2c *i2c, u8 scl);
|
||||
u32 data_reg;
|
||||
u8 max_nchan;
|
||||
};
|
||||
|
||||
#define RTL9300_I2C_MUX_NCHAN 8
|
||||
#define RTL9310_I2C_MUX_NCHAN 12
|
||||
|
||||
struct rtl9300_i2c {
|
||||
struct regmap *regmap;
|
||||
struct device *dev;
|
||||
struct rtl9300_i2c_chan chans[RTL9300_I2C_MUX_NCHAN];
|
||||
struct rtl9300_i2c_chan chans[RTL9310_I2C_MUX_NCHAN];
|
||||
struct regmap_field *fields[F_NUM_FIELDS];
|
||||
u32 reg_base;
|
||||
u8 sda_pin;
|
||||
u32 data_reg;
|
||||
u8 scl_num;
|
||||
u8 sda_num;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
DEFINE_GUARD(rtl9300_i2c, struct rtl9300_i2c *, mutex_lock(&_T->lock), mutex_unlock(&_T->lock))
|
||||
|
||||
enum rtl9300_i2c_xfer_type {
|
||||
RTL9300_I2C_XFER_BYTE,
|
||||
RTL9300_I2C_XFER_WORD,
|
||||
RTL9300_I2C_XFER_BLOCK,
|
||||
};
|
||||
|
||||
struct rtl9300_i2c_xfer {
|
||||
enum rtl9300_i2c_xfer_type type;
|
||||
u16 dev_addr;
|
||||
u8 reg_addr;
|
||||
u8 reg_addr_len;
|
||||
u8 *data;
|
||||
u8 data_len;
|
||||
bool write;
|
||||
};
|
||||
|
||||
#define RTL9300_I2C_MST_CTRL1 0x0
|
||||
#define RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS 8
|
||||
#define RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK GENMASK(31, 8)
|
||||
#define RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS 4
|
||||
#define RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK GENMASK(6, 4)
|
||||
#define RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL BIT(3)
|
||||
#define RTL9300_I2C_MST_CTRL1_RWOP BIT(2)
|
||||
#define RTL9300_I2C_MST_CTRL1_I2C_FAIL BIT(1)
|
||||
#define RTL9300_I2C_MST_CTRL1_I2C_TRIG BIT(0)
|
||||
#define RTL9300_I2C_MST_CTRL2 0x4
|
||||
#define RTL9300_I2C_MST_CTRL2_RD_MODE BIT(15)
|
||||
#define RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS 8
|
||||
#define RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK GENMASK(14, 8)
|
||||
#define RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS 4
|
||||
#define RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK GENMASK(7, 4)
|
||||
#define RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS 2
|
||||
#define RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK GENMASK(3, 2)
|
||||
#define RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS 0
|
||||
#define RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK GENMASK(1, 0)
|
||||
#define RTL9300_I2C_MST_DATA_WORD0 0x8
|
||||
#define RTL9300_I2C_MST_DATA_WORD1 0xc
|
||||
#define RTL9300_I2C_MST_DATA_WORD2 0x10
|
||||
#define RTL9300_I2C_MST_DATA_WORD3 0x14
|
||||
|
||||
#define RTL9300_I2C_MST_GLB_CTRL 0x384
|
||||
|
||||
#define RTL9310_I2C_MST_IF_CTRL 0x1004
|
||||
#define RTL9310_I2C_MST_IF_SEL 0x1008
|
||||
#define RTL9310_I2C_MST_CTRL 0x0
|
||||
#define RTL9310_I2C_MST_MEMADDR_CTRL 0x4
|
||||
#define RTL9310_I2C_MST_DATA_CTRL 0x8
|
||||
|
||||
static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len)
|
||||
{
|
||||
u32 val, mask;
|
||||
int ret;
|
||||
|
||||
val = len << RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS;
|
||||
mask = RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK;
|
||||
|
||||
ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val);
|
||||
ret = regmap_field_write(i2c->fields[F_MEM_ADDR_WIDTH], len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = reg << RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS;
|
||||
mask = RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK;
|
||||
|
||||
return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val);
|
||||
return regmap_field_write(i2c->fields[F_MEM_ADDR], reg);
|
||||
}
|
||||
|
||||
static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, u8 sda_pin)
|
||||
static int rtl9300_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl)
|
||||
{
|
||||
int ret;
|
||||
u32 val, mask;
|
||||
return regmap_field_write(i2c->fields[F_SCL_SEL], 1);
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(i2c->regmap, RTL9300_I2C_MST_GLB_CTRL, BIT(sda_pin), BIT(sda_pin));
|
||||
static int rtl9310_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl)
|
||||
{
|
||||
return regmap_field_update_bits(i2c->fields[F_SCL_SEL], BIT(scl), BIT(scl));
|
||||
}
|
||||
|
||||
static int rtl9300_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan)
|
||||
{
|
||||
struct rtl9300_i2c_drv_data *drv_data;
|
||||
int ret;
|
||||
|
||||
if (i2c->sda_num == chan->sda_num)
|
||||
return 0;
|
||||
|
||||
ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = (sda_pin << RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS) |
|
||||
RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL;
|
||||
mask = RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK | RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL;
|
||||
drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
|
||||
ret = drv_data->select_scl(i2c, i2c->scl_num);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val);
|
||||
ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(chan->sda_num),
|
||||
BIT(chan->sda_num));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], chan->sda_num);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i2c->sda_num = chan->sda_num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan,
|
||||
u16 addr, u16 len)
|
||||
{
|
||||
u32 val, mask;
|
||||
|
||||
if (len < 1 || len > 16)
|
||||
return -EINVAL;
|
||||
|
||||
val = chan->bus_freq << RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS;
|
||||
mask = RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK;
|
||||
|
||||
val |= addr << RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS;
|
||||
mask |= RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK;
|
||||
|
||||
val |= ((len - 1) & 0xf) << RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS;
|
||||
mask |= RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK;
|
||||
|
||||
mask |= RTL9300_I2C_MST_CTRL2_RD_MODE;
|
||||
|
||||
return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val);
|
||||
}
|
||||
|
||||
static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
|
||||
static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
|
||||
{
|
||||
u32 vals[4] = {};
|
||||
int i, ret;
|
||||
@@ -124,8 +165,7 @@ static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
|
||||
if (len > 16)
|
||||
return -EIO;
|
||||
|
||||
ret = regmap_bulk_read(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0,
|
||||
vals, ARRAY_SIZE(vals));
|
||||
ret = regmap_bulk_read(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -137,7 +177,7 @@ static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len)
|
||||
static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
|
||||
{
|
||||
u32 vals[4] = {};
|
||||
int i;
|
||||
@@ -152,56 +192,94 @@ static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len)
|
||||
vals[reg] |= buf[i] << shift;
|
||||
}
|
||||
|
||||
return regmap_bulk_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0,
|
||||
vals, ARRAY_SIZE(vals));
|
||||
return regmap_bulk_write(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals));
|
||||
}
|
||||
|
||||
static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data)
|
||||
{
|
||||
return regmap_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, data);
|
||||
return regmap_write(i2c->regmap, i2c->data_reg, data);
|
||||
}
|
||||
|
||||
static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write,
|
||||
int size, union i2c_smbus_data *data, int len)
|
||||
static int rtl9300_i2c_prepare_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
|
||||
{
|
||||
u32 val, mask;
|
||||
int ret;
|
||||
|
||||
val = read_write == I2C_SMBUS_WRITE ? RTL9300_I2C_MST_CTRL1_RWOP : 0;
|
||||
mask = RTL9300_I2C_MST_CTRL1_RWOP;
|
||||
if (xfer->data_len < 1 || xfer->data_len > 16)
|
||||
return -EINVAL;
|
||||
|
||||
val |= RTL9300_I2C_MST_CTRL1_I2C_TRIG;
|
||||
mask |= RTL9300_I2C_MST_CTRL1_I2C_TRIG;
|
||||
|
||||
ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val);
|
||||
ret = regmap_field_write(i2c->fields[F_DEV_ADDR], xfer->dev_addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read_poll_timeout(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1,
|
||||
val, !(val & RTL9300_I2C_MST_CTRL1_I2C_TRIG), 100, 100000);
|
||||
ret = rtl9300_i2c_reg_addr_set(i2c, xfer->reg_addr, xfer->reg_addr_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val & RTL9300_I2C_MST_CTRL1_I2C_FAIL)
|
||||
ret = regmap_field_write(i2c->fields[F_RWOP], xfer->write);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_field_write(i2c->fields[F_DATA_WIDTH], (xfer->data_len - 1) & 0xf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (xfer->write) {
|
||||
switch (xfer->type) {
|
||||
case RTL9300_I2C_XFER_BYTE:
|
||||
ret = rtl9300_i2c_writel(i2c, *xfer->data);
|
||||
break;
|
||||
case RTL9300_I2C_XFER_WORD:
|
||||
ret = rtl9300_i2c_writel(i2c, get_unaligned((const u16 *)xfer->data));
|
||||
break;
|
||||
default:
|
||||
ret = rtl9300_i2c_write(i2c, xfer->data, xfer->data_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rtl9300_i2c_do_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_field_write(i2c->fields[F_I2C_TRIG], 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_field_read_poll_timeout(i2c->fields[F_I2C_TRIG], val, !val, 100, 100000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_field_read(i2c->fields[F_I2C_FAIL], &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (val)
|
||||
return -EIO;
|
||||
|
||||
if (read_write == I2C_SMBUS_READ) {
|
||||
if (size == I2C_SMBUS_BYTE || size == I2C_SMBUS_BYTE_DATA) {
|
||||
ret = regmap_read(i2c->regmap,
|
||||
i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val);
|
||||
if (!xfer->write) {
|
||||
switch (xfer->type) {
|
||||
case RTL9300_I2C_XFER_BYTE:
|
||||
ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
data->byte = val & 0xff;
|
||||
} else if (size == I2C_SMBUS_WORD_DATA) {
|
||||
ret = regmap_read(i2c->regmap,
|
||||
i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val);
|
||||
|
||||
*xfer->data = val & 0xff;
|
||||
break;
|
||||
case RTL9300_I2C_XFER_WORD:
|
||||
ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
data->word = val & 0xffff;
|
||||
} else {
|
||||
ret = rtl9300_i2c_read(i2c, &data->block[0], len);
|
||||
|
||||
put_unaligned(val & 0xffff, (u16*)xfer->data);
|
||||
break;
|
||||
default:
|
||||
ret = rtl9300_i2c_read(i2c, xfer->data, xfer->data_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,100 +292,68 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
|
||||
{
|
||||
struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap);
|
||||
struct rtl9300_i2c *i2c = chan->i2c;
|
||||
int len = 0, ret;
|
||||
struct rtl9300_i2c_xfer xfer = {0};
|
||||
int ret;
|
||||
|
||||
mutex_lock(&i2c->lock);
|
||||
if (chan->sda_pin != i2c->sda_pin) {
|
||||
ret = rtl9300_i2c_config_io(i2c, chan->sda_pin);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
i2c->sda_pin = chan->sda_pin;
|
||||
}
|
||||
if (addr > 0x7f)
|
||||
return -EINVAL;
|
||||
|
||||
guard(rtl9300_i2c)(i2c);
|
||||
|
||||
ret = rtl9300_i2c_config_chan(i2c, chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
xfer.dev_addr = addr & 0x7f;
|
||||
xfer.write = (read_write == I2C_SMBUS_WRITE);
|
||||
xfer.reg_addr = command;
|
||||
xfer.reg_addr_len = 1;
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_BYTE:
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
} else {
|
||||
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
xfer.data = (read_write == I2C_SMBUS_READ) ? &data->byte : &command;
|
||||
xfer.data_len = 1;
|
||||
xfer.reg_addr = 0;
|
||||
xfer.reg_addr_len = 0;
|
||||
xfer.type = RTL9300_I2C_XFER_BYTE;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
ret = rtl9300_i2c_writel(i2c, data->byte);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
xfer.data = &data->byte;
|
||||
xfer.data_len = 1;
|
||||
xfer.type = RTL9300_I2C_XFER_BYTE;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 2);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
ret = rtl9300_i2c_writel(i2c, data->word);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
xfer.data = (u8 *)&data->word;
|
||||
xfer.data_len = 2;
|
||||
xfer.type = RTL9300_I2C_XFER_WORD;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0] + 1);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
ret = rtl9300_i2c_write(i2c, &data->block[0], data->block[0] + 1);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
len = data->block[0] + 1;
|
||||
xfer.data = &data->block[0];
|
||||
xfer.data_len = data->block[0] + 1;
|
||||
xfer.type = RTL9300_I2C_XFER_BLOCK;
|
||||
break;
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
xfer.data = &data->block[1];
|
||||
xfer.data_len = data->block[0];
|
||||
xfer.type = RTL9300_I2C_XFER_BLOCK;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&adap->dev, "Unsupported transaction %d\n", size);
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out_unlock;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = rtl9300_i2c_execute_xfer(i2c, read_write, size, data, len);
|
||||
ret = rtl9300_i2c_prepare_xfer(i2c, &xfer);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&i2c->lock);
|
||||
|
||||
return ret;
|
||||
return rtl9300_i2c_do_xfer(i2c, &xfer);
|
||||
}
|
||||
|
||||
static u32 rtl9300_i2c_func(struct i2c_adapter *a)
|
||||
{
|
||||
return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA;
|
||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm rtl9300_i2c_algo = {
|
||||
@@ -325,9 +371,11 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rtl9300_i2c *i2c;
|
||||
u32 clock_freq, sda_pin;
|
||||
int ret, i = 0;
|
||||
struct fwnode_handle *child;
|
||||
struct rtl9300_i2c_drv_data *drv_data;
|
||||
struct reg_field fields[F_NUM_FIELDS];
|
||||
u32 clock_freq, scl_num, sda_num;
|
||||
int ret, i = 0;
|
||||
|
||||
i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
|
||||
if (!i2c)
|
||||
@@ -344,16 +392,34 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = device_property_read_u32(dev, "realtek,scl", &scl_num);
|
||||
if (ret || scl_num != 1)
|
||||
scl_num = 0;
|
||||
i2c->scl_num = (u8)scl_num;
|
||||
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
if (device_get_child_node_count(dev) > RTL9300_I2C_MUX_NCHAN)
|
||||
drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
|
||||
if (device_get_child_node_count(dev) > drv_data->max_nchan)
|
||||
return dev_err_probe(dev, -EINVAL, "Too many channels\n");
|
||||
|
||||
i2c->data_reg = i2c->reg_base + drv_data->data_reg;
|
||||
for (i = 0; i < F_NUM_FIELDS; i++) {
|
||||
fields[i] = drv_data->field_desc[i].field;
|
||||
if (drv_data->field_desc[i].scope == REG_SCOPE_MASTER)
|
||||
fields[i].reg += i2c->reg_base;
|
||||
}
|
||||
ret = devm_regmap_field_bulk_alloc(dev, i2c->regmap, i2c->fields,
|
||||
fields, F_NUM_FIELDS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i = 0;
|
||||
device_for_each_child_node(dev, child) {
|
||||
struct rtl9300_i2c_chan *chan = &i2c->chans[i];
|
||||
struct i2c_adapter *adap = &chan->adap;
|
||||
|
||||
ret = fwnode_property_read_u32(child, "reg", &sda_pin);
|
||||
ret = fwnode_property_read_u32(child, "reg", &sda_num);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -365,17 +431,16 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
|
||||
case I2C_MAX_STANDARD_MODE_FREQ:
|
||||
chan->bus_freq = RTL9300_I2C_STD_FREQ;
|
||||
break;
|
||||
|
||||
case I2C_MAX_FAST_MODE_FREQ:
|
||||
chan->bus_freq = RTL9300_I2C_FAST_FREQ;
|
||||
break;
|
||||
default:
|
||||
dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n",
|
||||
sda_pin, clock_freq);
|
||||
sda_num, clock_freq);
|
||||
break;
|
||||
}
|
||||
|
||||
chan->sda_pin = sda_pin;
|
||||
chan->sda_num = sda_num;
|
||||
chan->i2c = i2c;
|
||||
adap = &i2c->chans[i].adap;
|
||||
adap->owner = THIS_MODULE;
|
||||
@@ -385,23 +450,77 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
|
||||
adap->dev.parent = dev;
|
||||
i2c_set_adapdata(adap, chan);
|
||||
adap->dev.of_node = to_of_node(child);
|
||||
snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_pin);
|
||||
snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_num);
|
||||
i++;
|
||||
|
||||
ret = devm_i2c_add_adapter(dev, adap);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
i2c->sda_pin = 0xff;
|
||||
i2c->sda_num = 0xff;
|
||||
|
||||
/* only use standard read format */
|
||||
ret = regmap_field_write(i2c->fields[F_RD_MODE], 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GLB_REG_FIELD(reg, msb, lsb) \
|
||||
{ .field = REG_FIELD(reg, msb, lsb), .scope = REG_SCOPE_GLOBAL }
|
||||
#define MST_REG_FIELD(reg, msb, lsb) \
|
||||
{ .field = REG_FIELD(reg, msb, lsb), .scope = REG_SCOPE_MASTER }
|
||||
|
||||
static const struct rtl9300_i2c_drv_data rtl9300_i2c_drv_data = {
|
||||
.field_desc = {
|
||||
[F_MEM_ADDR] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 8, 31),
|
||||
[F_SDA_OUT_SEL] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 4, 6),
|
||||
[F_SCL_SEL] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 3, 3),
|
||||
[F_RWOP] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 2, 2),
|
||||
[F_I2C_FAIL] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 1, 1),
|
||||
[F_I2C_TRIG] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 0, 0),
|
||||
[F_RD_MODE] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 15, 15),
|
||||
[F_DEV_ADDR] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 8, 14),
|
||||
[F_DATA_WIDTH] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 4, 7),
|
||||
[F_MEM_ADDR_WIDTH] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 2, 3),
|
||||
[F_SCL_FREQ] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 0, 1),
|
||||
[F_SDA_SEL] = GLB_REG_FIELD(RTL9300_I2C_MST_GLB_CTRL, 0, 7),
|
||||
},
|
||||
.select_scl = rtl9300_i2c_select_scl,
|
||||
.data_reg = RTL9300_I2C_MST_DATA_WORD0,
|
||||
.max_nchan = RTL9300_I2C_MUX_NCHAN,
|
||||
};
|
||||
|
||||
static const struct rtl9300_i2c_drv_data rtl9310_i2c_drv_data = {
|
||||
.field_desc = {
|
||||
[F_SCL_SEL] = GLB_REG_FIELD(RTL9310_I2C_MST_IF_SEL, 12, 13),
|
||||
[F_SDA_SEL] = GLB_REG_FIELD(RTL9310_I2C_MST_IF_SEL, 0, 11),
|
||||
[F_SCL_FREQ] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 30, 31),
|
||||
[F_DEV_ADDR] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 11, 17),
|
||||
[F_SDA_OUT_SEL] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 18, 21),
|
||||
[F_MEM_ADDR_WIDTH] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 9, 10),
|
||||
[F_DATA_WIDTH] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 5, 8),
|
||||
[F_RD_MODE] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 4, 4),
|
||||
[F_RWOP] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 2, 2),
|
||||
[F_I2C_FAIL] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 1, 1),
|
||||
[F_I2C_TRIG] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 0, 0),
|
||||
[F_MEM_ADDR] = MST_REG_FIELD(RTL9310_I2C_MST_MEMADDR_CTRL, 0, 23),
|
||||
},
|
||||
.select_scl = rtl9310_i2c_select_scl,
|
||||
.data_reg = RTL9310_I2C_MST_DATA_CTRL,
|
||||
.max_nchan = RTL9310_I2C_MUX_NCHAN,
|
||||
};
|
||||
|
||||
static const struct of_device_id i2c_rtl9300_dt_ids[] = {
|
||||
{ .compatible = "realtek,rtl9301-i2c" },
|
||||
{ .compatible = "realtek,rtl9302b-i2c" },
|
||||
{ .compatible = "realtek,rtl9302c-i2c" },
|
||||
{ .compatible = "realtek,rtl9303-i2c" },
|
||||
{ .compatible = "realtek,rtl9301-i2c", .data = (void *) &rtl9300_i2c_drv_data },
|
||||
{ .compatible = "realtek,rtl9302b-i2c", .data = (void *) &rtl9300_i2c_drv_data },
|
||||
{ .compatible = "realtek,rtl9302c-i2c", .data = (void *) &rtl9300_i2c_drv_data },
|
||||
{ .compatible = "realtek,rtl9303-i2c", .data = (void *) &rtl9300_i2c_drv_data },
|
||||
{ .compatible = "realtek,rtl9310-i2c", .data = (void *) &rtl9310_i2c_drv_data },
|
||||
{ .compatible = "realtek,rtl9311-i2c", .data = (void *) &rtl9310_i2c_drv_data },
|
||||
{ .compatible = "realtek,rtl9312-i2c", .data = (void *) &rtl9310_i2c_drv_data },
|
||||
{ .compatible = "realtek,rtl9313-i2c", .data = (void *) &rtl9310_i2c_drv_data },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids);
|
||||
|
||||
@@ -197,13 +197,22 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
|
||||
|
||||
static int amd_ntb_get_link_status(struct amd_ntb_dev *ndev)
|
||||
{
|
||||
struct pci_dev *pdev = NULL;
|
||||
struct pci_dev *pdev = ndev->ntb.pdev;
|
||||
struct pci_dev *pci_swds = NULL;
|
||||
struct pci_dev *pci_swus = NULL;
|
||||
u32 stat;
|
||||
int rc;
|
||||
|
||||
if (ndev->ntb.topo == NTB_TOPO_SEC) {
|
||||
if (ndev->dev_data->is_endpoint) {
|
||||
rc = pcie_capability_read_dword(pdev, PCI_EXP_LNKCTL, &stat);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
ndev->lnk_sta = stat;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Locate the pointer to Downstream Switch for this device */
|
||||
pci_swds = pci_upstream_bridge(ndev->ntb.pdev);
|
||||
if (pci_swds) {
|
||||
@@ -1311,6 +1320,11 @@ static const struct ntb_dev_data dev_data[] = {
|
||||
.mw_count = 2,
|
||||
.mw_idx = 2,
|
||||
},
|
||||
{ /* for device 0x17d7 */
|
||||
.mw_count = 2,
|
||||
.mw_idx = 2,
|
||||
.is_endpoint = true,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pci_device_id amd_ntb_pci_tbl[] = {
|
||||
@@ -1319,6 +1333,8 @@ static const struct pci_device_id amd_ntb_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(AMD, 0x14c0), (kernel_ulong_t)&dev_data[1] },
|
||||
{ PCI_VDEVICE(AMD, 0x14c3), (kernel_ulong_t)&dev_data[1] },
|
||||
{ PCI_VDEVICE(AMD, 0x155a), (kernel_ulong_t)&dev_data[1] },
|
||||
{ PCI_VDEVICE(AMD, 0x17d4), (kernel_ulong_t)&dev_data[1] },
|
||||
{ PCI_VDEVICE(AMD, 0x17d7), (kernel_ulong_t)&dev_data[2] },
|
||||
{ PCI_VDEVICE(HYGON, 0x145b), (kernel_ulong_t)&dev_data[0] },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
@@ -168,6 +168,7 @@ enum {
|
||||
struct ntb_dev_data {
|
||||
const unsigned char mw_count;
|
||||
const unsigned int mw_idx;
|
||||
const bool is_endpoint;
|
||||
};
|
||||
|
||||
struct amd_ntb_dev;
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#define NTB_EPF_COMMAND_TIMEOUT 1000 /* 1 Sec */
|
||||
|
||||
enum pci_barno {
|
||||
NO_BAR = -1,
|
||||
BAR_0,
|
||||
BAR_1,
|
||||
BAR_2,
|
||||
@@ -57,16 +58,26 @@ enum pci_barno {
|
||||
BAR_5,
|
||||
};
|
||||
|
||||
enum epf_ntb_bar {
|
||||
BAR_CONFIG,
|
||||
BAR_PEER_SPAD,
|
||||
BAR_DB,
|
||||
BAR_MW1,
|
||||
BAR_MW2,
|
||||
BAR_MW3,
|
||||
BAR_MW4,
|
||||
NTB_BAR_NUM,
|
||||
};
|
||||
|
||||
#define NTB_EPF_MAX_MW_COUNT (NTB_BAR_NUM - BAR_MW1)
|
||||
|
||||
struct ntb_epf_dev {
|
||||
struct ntb_dev ntb;
|
||||
struct device *dev;
|
||||
/* Mutex to protect providing commands to NTB EPF */
|
||||
struct mutex cmd_lock;
|
||||
|
||||
enum pci_barno ctrl_reg_bar;
|
||||
enum pci_barno peer_spad_reg_bar;
|
||||
enum pci_barno db_reg_bar;
|
||||
enum pci_barno mw_bar;
|
||||
const enum pci_barno *barno_map;
|
||||
|
||||
unsigned int mw_count;
|
||||
unsigned int spad_count;
|
||||
@@ -85,17 +96,6 @@ struct ntb_epf_dev {
|
||||
|
||||
#define ntb_ndev(__ntb) container_of(__ntb, struct ntb_epf_dev, ntb)
|
||||
|
||||
struct ntb_epf_data {
|
||||
/* BAR that contains both control region and self spad region */
|
||||
enum pci_barno ctrl_reg_bar;
|
||||
/* BAR that contains peer spad region */
|
||||
enum pci_barno peer_spad_reg_bar;
|
||||
/* BAR that contains Doorbell region and Memory window '1' */
|
||||
enum pci_barno db_reg_bar;
|
||||
/* BAR that contains memory windows*/
|
||||
enum pci_barno mw_bar;
|
||||
};
|
||||
|
||||
static int ntb_epf_send_command(struct ntb_epf_dev *ndev, u32 command,
|
||||
u32 argument)
|
||||
{
|
||||
@@ -144,7 +144,7 @@ static int ntb_epf_mw_to_bar(struct ntb_epf_dev *ndev, int idx)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return idx + 2;
|
||||
return ndev->barno_map[BAR_MW1 + idx];
|
||||
}
|
||||
|
||||
static int ntb_epf_mw_count(struct ntb_dev *ntb, int pidx)
|
||||
@@ -413,7 +413,9 @@ static int ntb_epf_mw_set_trans(struct ntb_dev *ntb, int pidx, int idx,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bar = idx + ndev->mw_bar;
|
||||
bar = ntb_epf_mw_to_bar(ndev, idx);
|
||||
if (bar < 0)
|
||||
return bar;
|
||||
|
||||
mw_size = pci_resource_len(ntb->pdev, bar);
|
||||
|
||||
@@ -455,7 +457,9 @@ static int ntb_epf_peer_mw_get_addr(struct ntb_dev *ntb, int idx,
|
||||
if (idx == 0)
|
||||
offset = readl(ndev->ctrl_reg + NTB_EPF_MW1_OFFSET);
|
||||
|
||||
bar = idx + ndev->mw_bar;
|
||||
bar = ntb_epf_mw_to_bar(ndev, idx);
|
||||
if (bar < 0)
|
||||
return bar;
|
||||
|
||||
if (base)
|
||||
*base = pci_resource_start(ndev->ntb.pdev, bar) + offset;
|
||||
@@ -560,6 +564,11 @@ static int ntb_epf_init_dev(struct ntb_epf_dev *ndev)
|
||||
ndev->mw_count = readl(ndev->ctrl_reg + NTB_EPF_MW_COUNT);
|
||||
ndev->spad_count = readl(ndev->ctrl_reg + NTB_EPF_SPAD_COUNT);
|
||||
|
||||
if (ndev->mw_count > NTB_EPF_MAX_MW_COUNT) {
|
||||
dev_err(dev, "Unsupported MW count: %u\n", ndev->mw_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -596,14 +605,15 @@ static int ntb_epf_init_pci(struct ntb_epf_dev *ndev,
|
||||
dev_warn(&pdev->dev, "Cannot DMA highmem\n");
|
||||
}
|
||||
|
||||
ndev->ctrl_reg = pci_iomap(pdev, ndev->ctrl_reg_bar, 0);
|
||||
ndev->ctrl_reg = pci_iomap(pdev, ndev->barno_map[BAR_CONFIG], 0);
|
||||
if (!ndev->ctrl_reg) {
|
||||
ret = -EIO;
|
||||
goto err_pci_regions;
|
||||
}
|
||||
|
||||
if (ndev->peer_spad_reg_bar) {
|
||||
ndev->peer_spad_reg = pci_iomap(pdev, ndev->peer_spad_reg_bar, 0);
|
||||
if (ndev->barno_map[BAR_PEER_SPAD] != ndev->barno_map[BAR_CONFIG]) {
|
||||
ndev->peer_spad_reg = pci_iomap(pdev,
|
||||
ndev->barno_map[BAR_PEER_SPAD], 0);
|
||||
if (!ndev->peer_spad_reg) {
|
||||
ret = -EIO;
|
||||
goto err_pci_regions;
|
||||
@@ -614,7 +624,7 @@ static int ntb_epf_init_pci(struct ntb_epf_dev *ndev,
|
||||
ndev->peer_spad_reg = ndev->ctrl_reg + spad_off + spad_sz;
|
||||
}
|
||||
|
||||
ndev->db_reg = pci_iomap(pdev, ndev->db_reg_bar, 0);
|
||||
ndev->db_reg = pci_iomap(pdev, ndev->barno_map[BAR_DB], 0);
|
||||
if (!ndev->db_reg) {
|
||||
ret = -EIO;
|
||||
goto err_pci_regions;
|
||||
@@ -659,12 +669,7 @@ static void ntb_epf_cleanup_isr(struct ntb_epf_dev *ndev)
|
||||
static int ntb_epf_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
enum pci_barno peer_spad_reg_bar = BAR_1;
|
||||
enum pci_barno ctrl_reg_bar = BAR_0;
|
||||
enum pci_barno db_reg_bar = BAR_2;
|
||||
enum pci_barno mw_bar = BAR_2;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ntb_epf_data *data;
|
||||
struct ntb_epf_dev *ndev;
|
||||
int ret;
|
||||
|
||||
@@ -675,18 +680,10 @@ static int ntb_epf_pci_probe(struct pci_dev *pdev,
|
||||
if (!ndev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = (struct ntb_epf_data *)id->driver_data;
|
||||
if (data) {
|
||||
peer_spad_reg_bar = data->peer_spad_reg_bar;
|
||||
ctrl_reg_bar = data->ctrl_reg_bar;
|
||||
db_reg_bar = data->db_reg_bar;
|
||||
mw_bar = data->mw_bar;
|
||||
}
|
||||
ndev->barno_map = (const enum pci_barno *)id->driver_data;
|
||||
if (!ndev->barno_map)
|
||||
return -EINVAL;
|
||||
|
||||
ndev->peer_spad_reg_bar = peer_spad_reg_bar;
|
||||
ndev->ctrl_reg_bar = ctrl_reg_bar;
|
||||
ndev->db_reg_bar = db_reg_bar;
|
||||
ndev->mw_bar = mw_bar;
|
||||
ndev->dev = dev;
|
||||
|
||||
ntb_epf_init_struct(ndev, pdev);
|
||||
@@ -730,30 +727,51 @@ static void ntb_epf_pci_remove(struct pci_dev *pdev)
|
||||
ntb_epf_deinit_pci(ndev);
|
||||
}
|
||||
|
||||
static const struct ntb_epf_data j721e_data = {
|
||||
.ctrl_reg_bar = BAR_0,
|
||||
.peer_spad_reg_bar = BAR_1,
|
||||
.db_reg_bar = BAR_2,
|
||||
.mw_bar = BAR_2,
|
||||
static const enum pci_barno j721e_map[NTB_BAR_NUM] = {
|
||||
[BAR_CONFIG] = BAR_0,
|
||||
[BAR_PEER_SPAD] = BAR_1,
|
||||
[BAR_DB] = BAR_2,
|
||||
[BAR_MW1] = BAR_2,
|
||||
[BAR_MW2] = BAR_3,
|
||||
[BAR_MW3] = BAR_4,
|
||||
[BAR_MW4] = BAR_5
|
||||
};
|
||||
|
||||
static const struct ntb_epf_data mx8_data = {
|
||||
.ctrl_reg_bar = BAR_0,
|
||||
.peer_spad_reg_bar = BAR_0,
|
||||
.db_reg_bar = BAR_2,
|
||||
.mw_bar = BAR_4,
|
||||
static const enum pci_barno mx8_map[NTB_BAR_NUM] = {
|
||||
[BAR_CONFIG] = BAR_0,
|
||||
[BAR_PEER_SPAD] = BAR_0,
|
||||
[BAR_DB] = BAR_2,
|
||||
[BAR_MW1] = BAR_4,
|
||||
[BAR_MW2] = BAR_5,
|
||||
[BAR_MW3] = NO_BAR,
|
||||
[BAR_MW4] = NO_BAR
|
||||
};
|
||||
|
||||
static const enum pci_barno rcar_barno[NTB_BAR_NUM] = {
|
||||
[BAR_CONFIG] = BAR_0,
|
||||
[BAR_PEER_SPAD] = BAR_0,
|
||||
[BAR_DB] = BAR_4,
|
||||
[BAR_MW1] = BAR_2,
|
||||
[BAR_MW2] = NO_BAR,
|
||||
[BAR_MW3] = NO_BAR,
|
||||
[BAR_MW4] = NO_BAR,
|
||||
};
|
||||
|
||||
static const struct pci_device_id ntb_epf_pci_tbl[] = {
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
|
||||
.class = PCI_CLASS_MEMORY_RAM << 8, .class_mask = 0xffff00,
|
||||
.driver_data = (kernel_ulong_t)&j721e_data,
|
||||
.driver_data = (kernel_ulong_t)j721e_map,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x0809),
|
||||
.class = PCI_CLASS_MEMORY_RAM << 8, .class_mask = 0xffff00,
|
||||
.driver_data = (kernel_ulong_t)&mx8_data,
|
||||
.driver_data = (kernel_ulong_t)mx8_map,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0030),
|
||||
.class = PCI_CLASS_MEMORY_RAM << 8, .class_mask = 0xffff00,
|
||||
.driver_data = (kernel_ulong_t)rcar_barno,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "linux/ntb.h"
|
||||
#include "linux/ntb_transport.h"
|
||||
|
||||
@@ -241,6 +242,9 @@ struct ntb_transport_ctx {
|
||||
struct work_struct link_cleanup;
|
||||
|
||||
struct dentry *debugfs_node_dir;
|
||||
|
||||
/* Make sure workq of link event be executed serially */
|
||||
struct mutex link_event_lock;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -1024,6 +1028,7 @@ static void ntb_transport_link_cleanup_work(struct work_struct *work)
|
||||
struct ntb_transport_ctx *nt =
|
||||
container_of(work, struct ntb_transport_ctx, link_cleanup);
|
||||
|
||||
guard(mutex)(&nt->link_event_lock);
|
||||
ntb_transport_link_cleanup(nt);
|
||||
}
|
||||
|
||||
@@ -1047,6 +1052,8 @@ static void ntb_transport_link_work(struct work_struct *work)
|
||||
u32 val;
|
||||
int rc = 0, i, spad;
|
||||
|
||||
guard(mutex)(&nt->link_event_lock);
|
||||
|
||||
/* send the local info, in the opposite order of the way we read it */
|
||||
|
||||
if (nt->use_msi) {
|
||||
|
||||
@@ -126,9 +126,9 @@ config FB_ACORN
|
||||
config FB_CLPS711X
|
||||
tristate "CLPS711X LCD support"
|
||||
depends on FB && (ARCH_CLPS711X || COMPILE_TEST)
|
||||
depends on LCD_CLASS_DEVICE
|
||||
select FB_IOMEM_HELPERS
|
||||
select FB_MODE_HELPERS
|
||||
select LCD_CLASS_DEVICE
|
||||
select VIDEOMODE_HELPERS
|
||||
help
|
||||
Say Y to enable the Framebuffer driver for the Cirrus Logic
|
||||
@@ -150,7 +150,7 @@ config FB_IMX
|
||||
tristate "Freescale i.MX1/21/25/27 LCD support"
|
||||
depends on FB && HAVE_CLK && HAS_IOMEM
|
||||
depends on ARCH_MXC || COMPILE_TEST
|
||||
select LCD_CLASS_DEVICE
|
||||
depends on LCD_CLASS_DEVICE
|
||||
select FB_IOMEM_HELPERS
|
||||
select FB_MODE_HELPERS
|
||||
select VIDEOMODE_HELPERS
|
||||
@@ -948,9 +948,6 @@ config FB_RADEON
|
||||
a framebuffer device. There are both PCI and AGP versions. You
|
||||
don't need to choose this to run the Radeon in plain VGA mode.
|
||||
|
||||
There is a product page at
|
||||
https://products.amd.com/en-us/GraphicCardResult.aspx
|
||||
|
||||
config FB_RADEON_I2C
|
||||
bool "DDC/I2C for ATI Radeon support"
|
||||
depends on FB_RADEON
|
||||
@@ -1060,6 +1057,7 @@ config FB_S3
|
||||
select FB_TILEBLITTING
|
||||
select FB_SVGALIB
|
||||
select VGASTATE
|
||||
select FB_CFB_REV_PIXELS_IN_BYTE
|
||||
select FONT_8x16 if FRAMEBUFFER_CONSOLE
|
||||
help
|
||||
Driver for graphics boards with S3 Trio / S3 Virge chip.
|
||||
|
||||
@@ -160,6 +160,11 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info,
|
||||
image.height = vc->vc_font.height;
|
||||
image.depth = 1;
|
||||
|
||||
if (image.dy >= info->var.yres)
|
||||
return;
|
||||
|
||||
image.height = min(image.height, info->var.yres - image.dy);
|
||||
|
||||
if (attribute) {
|
||||
buf = kmalloc(cellsize, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
@@ -173,6 +178,18 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info,
|
||||
cnt = count;
|
||||
|
||||
image.width = vc->vc_font.width * cnt;
|
||||
|
||||
if (image.dx >= info->var.xres)
|
||||
break;
|
||||
|
||||
if (image.dx + image.width > info->var.xres) {
|
||||
image.width = info->var.xres - image.dx;
|
||||
cnt = image.width / vc->vc_font.width;
|
||||
if (cnt == 0)
|
||||
break;
|
||||
image.width = cnt * vc->vc_font.width;
|
||||
}
|
||||
|
||||
pitch = DIV_ROUND_UP(image.width, 8) + scan_align;
|
||||
pitch &= ~scan_align;
|
||||
size = pitch * image.height + buf_align;
|
||||
|
||||
@@ -40,7 +40,7 @@ int fb_get_options(const char *name, char **option)
|
||||
bool enabled;
|
||||
|
||||
if (name)
|
||||
is_of = strncmp(name, "offb", 4);
|
||||
is_of = !strncmp(name, "offb", 4);
|
||||
|
||||
enabled = __video_get_options(name, &options, is_of);
|
||||
|
||||
|
||||
@@ -92,8 +92,7 @@ static unsigned long pixel_to_pat(int bpp, u32 color)
|
||||
pattern = pattern | pattern << bpp;
|
||||
break;
|
||||
default:
|
||||
pattern = color;
|
||||
break;
|
||||
return color;
|
||||
}
|
||||
#ifndef __LITTLE_ENDIAN
|
||||
pattern <<= (BITS_PER_LONG % bpp);
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <video/of_videomode.h>
|
||||
#include <video/videomode.h>
|
||||
#include "../edid.h"
|
||||
#include <linux/string_choices.h>
|
||||
|
||||
/*
|
||||
* EDID parser
|
||||
@@ -320,9 +321,9 @@ static void get_dpms_capabilities(unsigned char flags,
|
||||
if (flags & DPMS_STANDBY)
|
||||
specs->dpms |= FB_DPMS_STANDBY;
|
||||
DPRINTK(" DPMS: Active %s, Suspend %s, Standby %s\n",
|
||||
(flags & DPMS_ACTIVE_OFF) ? "yes" : "no",
|
||||
(flags & DPMS_SUSPEND) ? "yes" : "no",
|
||||
(flags & DPMS_STANDBY) ? "yes" : "no");
|
||||
str_yes_no(flags & DPMS_ACTIVE_OFF),
|
||||
str_yes_no(flags & DPMS_SUSPEND),
|
||||
str_yes_no(flags & DPMS_STANDBY));
|
||||
}
|
||||
|
||||
static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
|
||||
|
||||
@@ -674,7 +674,7 @@ static int of_platform_mb862xx_probe(struct platform_device *ofdev)
|
||||
struct fb_info *info;
|
||||
struct resource res;
|
||||
resource_size_t res_size;
|
||||
unsigned long ret = -ENODEV;
|
||||
int ret = -ENODEV;
|
||||
|
||||
if (of_address_to_resource(np, 0, &res)) {
|
||||
dev_err(dev, "Invalid address\n");
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/string_choices.h>
|
||||
#ifdef CONFIG_BOOTX_TEXT
|
||||
#include <asm/btext.h>
|
||||
#endif
|
||||
@@ -622,7 +623,7 @@ static int nvidiafb_set_par(struct fb_info *info)
|
||||
else
|
||||
par->FPDither = !!(NV_RD32(par->PRAMDAC, 0x083C) & 1);
|
||||
printk(KERN_INFO PFX "Flat panel dithering %s\n",
|
||||
par->FPDither ? "enabled" : "disabled");
|
||||
str_enabled_disabled(par->FPDither));
|
||||
}
|
||||
|
||||
info->fix.visual = (info->var.bits_per_pixel == 8) ?
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#include <linux/soc/pxa/cpu.h>
|
||||
#include <video/of_display_timing.h>
|
||||
#include <video/videomode.h>
|
||||
#include <linux/string_choices.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
@@ -1419,7 +1420,7 @@ static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
|
||||
|
||||
if (ret < 0)
|
||||
pr_warn("Unable to %s LCD supply regulator: %d\n",
|
||||
on ? "enable" : "disable", ret);
|
||||
str_enable_disable(on), ret);
|
||||
else
|
||||
fbi->lcd_supply_enabled = on;
|
||||
}
|
||||
|
||||
+123
-54
@@ -50,10 +50,14 @@ struct s3fb_info {
|
||||
static const struct svga_fb_format s3fb_formats[] = {
|
||||
{ 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
|
||||
FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP4, FB_VISUAL_PSEUDOCOLOR, 8, 16},
|
||||
{ 4, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 0,
|
||||
FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16},
|
||||
{ 1, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 0, 0}, 2,
|
||||
FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 32, 64},
|
||||
{ 2, {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0}, 2,
|
||||
FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 16, 32},
|
||||
{ 4, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 1,
|
||||
FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 8, 16},
|
||||
{ 4, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 2,
|
||||
FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16},
|
||||
{ 8, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
|
||||
FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 4, 8},
|
||||
{16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0,
|
||||
@@ -557,7 +561,7 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
||||
|
||||
/* 32bpp mode is not supported on VIRGE VX,
|
||||
24bpp is not supported on others */
|
||||
if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6))
|
||||
if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 9) : (rv == 8))
|
||||
rv = -EINVAL;
|
||||
|
||||
if (rv < 0) {
|
||||
@@ -607,7 +611,7 @@ static int s3fb_set_par(struct fb_info *info)
|
||||
struct s3fb_info *par = info->par;
|
||||
u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes;
|
||||
u32 bpp = info->var.bits_per_pixel;
|
||||
u32 htotal, hsstart;
|
||||
u32 htotal, hsstart, pel_msk;
|
||||
|
||||
if (bpp != 0) {
|
||||
info->fix.ypanstep = 1;
|
||||
@@ -617,9 +621,11 @@ static int s3fb_set_par(struct fb_info *info)
|
||||
info->tileops = NULL;
|
||||
|
||||
/* in 4bpp supports 8p wide tiles only, any tiles otherwise */
|
||||
if (bpp == 4) {
|
||||
if (bpp == 4 && (info->var.nonstd & 1) != 0) {
|
||||
int i;
|
||||
bitmap_zero(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
|
||||
set_bit(8 - 1, info->pixmap.blit_x);
|
||||
for (i = 8; i <= FB_MAX_BLIT_WIDTH; i += 8)
|
||||
set_bit(i - 1, info->pixmap.blit_x);
|
||||
} else {
|
||||
bitmap_fill(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH);
|
||||
}
|
||||
@@ -730,7 +736,7 @@ static int s3fb_set_par(struct fb_info *info)
|
||||
vga_wcrt(par->state.vgabase, 0x50, 0x00);
|
||||
vga_wcrt(par->state.vgabase, 0x67, 0x50);
|
||||
msleep(10); /* screen remains blank sometimes without this */
|
||||
vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09);
|
||||
vga_wcrt(par->state.vgabase, 0x63, (mode <= 4) ? 0x90 : 0x09);
|
||||
vga_wcrt(par->state.vgabase, 0x66, 0x90);
|
||||
}
|
||||
|
||||
@@ -763,12 +769,17 @@ static int s3fb_set_par(struct fb_info *info)
|
||||
svga_wcrt_mask(par->state.vgabase, 0x31, 0x00, 0x40);
|
||||
multiplex = 0;
|
||||
hmul = 1;
|
||||
pel_msk = 0xff;
|
||||
|
||||
svga_wcrt_mask(par->state.vgabase, 0x08, 0x00, 0x60);
|
||||
svga_wcrt_mask(par->state.vgabase, 0x05, 0x00, 0x60);
|
||||
|
||||
/* Set mode-specific register values */
|
||||
switch (mode) {
|
||||
case 0:
|
||||
fb_dbg(info, "text mode\n");
|
||||
svga_set_textmode_vga_regs(par->state.vgabase);
|
||||
pel_msk = 0x0f;
|
||||
|
||||
/* Set additional registers like in 8-bit mode */
|
||||
svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
|
||||
@@ -783,8 +794,11 @@ static int s3fb_set_par(struct fb_info *info)
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
fb_dbg(info, "4 bit pseudocolor\n");
|
||||
vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40);
|
||||
fb_dbg(info, "1 bit pseudocolor\n");
|
||||
svga_wseq_mask(par->state.vgabase, 0x01, 0x10, 0x14);
|
||||
svga_wcrt_mask(par->state.vgabase, 0x08, 0x60, 0x60);
|
||||
svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60);
|
||||
pel_msk = 0x01;
|
||||
|
||||
/* Set additional registers like in 8-bit mode */
|
||||
svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
|
||||
@@ -794,7 +808,13 @@ static int s3fb_set_par(struct fb_info *info)
|
||||
svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
|
||||
break;
|
||||
case 2:
|
||||
fb_dbg(info, "4 bit pseudocolor, planar\n");
|
||||
fb_dbg(info, "2 bit pseudocolor\n");
|
||||
svga_wseq_mask(par->state.vgabase, 0x01, 0x04, 0x14);
|
||||
svga_wseq_mask(par->state.vgabase, 0x04, 0x08, 0x08);
|
||||
vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x20);
|
||||
svga_wcrt_mask(par->state.vgabase, 0x08, 0x20, 0x60);
|
||||
svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60);
|
||||
pel_msk = 0x03;
|
||||
|
||||
/* Set additional registers like in 8-bit mode */
|
||||
svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
|
||||
@@ -804,8 +824,35 @@ static int s3fb_set_par(struct fb_info *info)
|
||||
svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
|
||||
break;
|
||||
case 3:
|
||||
fb_dbg(info, "4 bit pseudocolor, planar\n");
|
||||
pel_msk = 0x0f;
|
||||
|
||||
/* Set additional registers like in 8-bit mode */
|
||||
svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
|
||||
svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
|
||||
svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60);
|
||||
|
||||
/* disable enhanced mode */
|
||||
svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
|
||||
break;
|
||||
case 4:
|
||||
fb_dbg(info, "4 bit pseudocolor\n");
|
||||
vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40);
|
||||
svga_wattr(par->state.vgabase, 0x33, 0x01);
|
||||
svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60);
|
||||
pel_msk = 0xf0;
|
||||
|
||||
/* Set additional registers like in 8-bit mode */
|
||||
svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
|
||||
svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
|
||||
|
||||
/* disable enhanced mode */
|
||||
svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
|
||||
break;
|
||||
case 5:
|
||||
fb_dbg(info, "8 bit pseudocolor\n");
|
||||
svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
|
||||
svga_wcrt_mask(par->state.vgabase, 0x05, 0x20, 0x60);
|
||||
if (info->var.pixclock > 20000 ||
|
||||
par->chip == CHIP_357_VIRGE_GX2 ||
|
||||
par->chip == CHIP_359_VIRGE_GX2P ||
|
||||
@@ -819,7 +866,7 @@ static int s3fb_set_par(struct fb_info *info)
|
||||
multiplex = 1;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
fb_dbg(info, "5/5/5 truecolor\n");
|
||||
if (par->chip == CHIP_988_VIRGE_VX) {
|
||||
if (info->var.pixclock > 20000)
|
||||
@@ -847,7 +894,7 @@ static int s3fb_set_par(struct fb_info *info)
|
||||
hmul = 2;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
case 7:
|
||||
fb_dbg(info, "5/6/5 truecolor\n");
|
||||
if (par->chip == CHIP_988_VIRGE_VX) {
|
||||
if (info->var.pixclock > 20000)
|
||||
@@ -875,12 +922,12 @@ static int s3fb_set_par(struct fb_info *info)
|
||||
hmul = 2;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
case 8:
|
||||
/* VIRGE VX case */
|
||||
fb_dbg(info, "8/8/8 truecolor\n");
|
||||
svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0);
|
||||
break;
|
||||
case 7:
|
||||
case 9:
|
||||
fb_dbg(info, "8/8/8/8 truecolor\n");
|
||||
svga_wcrt_mask(par->state.vgabase, 0x50, 0x30, 0x30);
|
||||
svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0);
|
||||
@@ -889,6 +936,7 @@ static int s3fb_set_par(struct fb_info *info)
|
||||
fb_err(info, "unsupported mode - bug\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
vga_w(par->state.vgabase, VGA_PEL_MSK, pel_msk);
|
||||
|
||||
if (par->chip != CHIP_988_VIRGE_VX) {
|
||||
svga_wseq_mask(par->state.vgabase, 0x15, multiplex ? 0x10 : 0x00, 0x10);
|
||||
@@ -927,33 +975,26 @@ static int s3fb_set_par(struct fb_info *info)
|
||||
static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
|
||||
u_int transp, struct fb_info *fb)
|
||||
{
|
||||
struct s3fb_info *par = fb->par;
|
||||
int cols;
|
||||
|
||||
switch (fb->var.bits_per_pixel) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
if (regno >= 16)
|
||||
return -EINVAL;
|
||||
|
||||
if ((fb->var.bits_per_pixel == 4) &&
|
||||
(fb->var.nonstd == 0)) {
|
||||
outb(0xF0, VGA_PEL_MSK);
|
||||
outb(regno*16, VGA_PEL_IW);
|
||||
} else {
|
||||
outb(0x0F, VGA_PEL_MSK);
|
||||
outb(regno, VGA_PEL_IW);
|
||||
}
|
||||
outb(red >> 10, VGA_PEL_D);
|
||||
outb(green >> 10, VGA_PEL_D);
|
||||
outb(blue >> 10, VGA_PEL_D);
|
||||
break;
|
||||
case 8:
|
||||
if (regno >= 256)
|
||||
cols = 1 << (fb->var.bits_per_pixel ? fb->var.bits_per_pixel : 4);
|
||||
if (regno >= cols)
|
||||
return -EINVAL;
|
||||
|
||||
outb(0xFF, VGA_PEL_MSK);
|
||||
outb(regno, VGA_PEL_IW);
|
||||
outb(red >> 10, VGA_PEL_D);
|
||||
outb(green >> 10, VGA_PEL_D);
|
||||
outb(blue >> 10, VGA_PEL_D);
|
||||
if ((fb->var.bits_per_pixel == 4) && ((fb->var.nonstd & 1) == 0))
|
||||
regno <<= 4;
|
||||
|
||||
vga_w(par->state.vgabase, VGA_PEL_IW, regno);
|
||||
vga_w(par->state.vgabase, VGA_PEL_D, red >> 10);
|
||||
vga_w(par->state.vgabase, VGA_PEL_D, green >> 10);
|
||||
vga_w(par->state.vgabase, VGA_PEL_D, blue >> 10);
|
||||
break;
|
||||
case 16:
|
||||
if (regno >= 16)
|
||||
@@ -988,34 +1029,30 @@ static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
|
||||
static int s3fb_blank(int blank_mode, struct fb_info *info)
|
||||
{
|
||||
struct s3fb_info *par = info->par;
|
||||
u8 data;
|
||||
|
||||
data = (blank_mode == FB_BLANK_UNBLANK) ? 0x00 : 0x20;
|
||||
svga_wseq_mask(par->state.vgabase, 0x01, data, 0x20);
|
||||
svga_wseq_mask(par->state.vgabase, 0x18, data, 0x20);
|
||||
|
||||
switch (blank_mode) {
|
||||
case FB_BLANK_UNBLANK:
|
||||
fb_dbg(info, "unblank\n");
|
||||
svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06);
|
||||
svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20);
|
||||
break;
|
||||
case FB_BLANK_NORMAL:
|
||||
fb_dbg(info, "blank\n");
|
||||
svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06);
|
||||
svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
|
||||
default:
|
||||
data = 0x00;
|
||||
break;
|
||||
case FB_BLANK_HSYNC_SUSPEND:
|
||||
fb_dbg(info, "hsync\n");
|
||||
svga_wcrt_mask(par->state.vgabase, 0x56, 0x02, 0x06);
|
||||
svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
|
||||
data = 0x02;
|
||||
break;
|
||||
case FB_BLANK_VSYNC_SUSPEND:
|
||||
fb_dbg(info, "vsync\n");
|
||||
svga_wcrt_mask(par->state.vgabase, 0x56, 0x04, 0x06);
|
||||
svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
|
||||
data = 0x04;
|
||||
break;
|
||||
case FB_BLANK_POWERDOWN:
|
||||
fb_dbg(info, "sync down\n");
|
||||
svga_wcrt_mask(par->state.vgabase, 0x56, 0x06, 0x06);
|
||||
svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
|
||||
data = 0x06;
|
||||
break;
|
||||
}
|
||||
svga_wcrt_mask(par->state.vgabase, 0x56, data, 0x06);
|
||||
|
||||
data = (blank_mode == FB_BLANK_POWERDOWN) ? 0x01 : 0x00;
|
||||
svga_wseq_mask(par->state.vgabase, 0x14, data, 0x01);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1045,6 +1082,33 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get capabilities of accelerator based on the mode */
|
||||
|
||||
static void s3fb_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
|
||||
struct fb_var_screeninfo *var)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (var->bits_per_pixel == 0) {
|
||||
/* can only support 256 8x16 bitmap */
|
||||
bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH);
|
||||
set_bit(8 - 1, caps->x);
|
||||
bitmap_zero(caps->y, FB_MAX_BLIT_HEIGHT);
|
||||
set_bit(16 - 1, caps->y);
|
||||
caps->len = 256;
|
||||
} else {
|
||||
if (var->bits_per_pixel == 4 && (var->nonstd & 1) != 0) {
|
||||
bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH);
|
||||
for (i = 8; i <= FB_MAX_BLIT_WIDTH; i += 8)
|
||||
set_bit(i - 1, caps->x);
|
||||
} else {
|
||||
bitmap_fill(caps->x, FB_MAX_BLIT_WIDTH);
|
||||
}
|
||||
bitmap_fill(caps->y, FB_MAX_BLIT_HEIGHT);
|
||||
caps->len = ~(u32)0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Frame buffer operations */
|
||||
@@ -1063,7 +1127,7 @@ static const struct fb_ops s3fb_ops = {
|
||||
.fb_copyarea = cfb_copyarea,
|
||||
.fb_imageblit = s3fb_imageblit,
|
||||
__FB_DEFAULT_IOMEM_OPS_MMAP,
|
||||
.fb_get_caps = svga_get_caps,
|
||||
.fb_get_caps = s3fb_get_caps,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
@@ -1445,6 +1509,8 @@ static int __maybe_unused s3_pci_suspend(struct device *dev)
|
||||
}
|
||||
|
||||
fb_set_suspend(info, 1);
|
||||
svga_wseq_mask(par->state.vgabase, 0x18, 0x20, 0x20);
|
||||
svga_wseq_mask(par->state.vgabase, 0x14, 0x01, 0x01);
|
||||
|
||||
mutex_unlock(&(par->open_lock));
|
||||
console_unlock();
|
||||
@@ -1471,6 +1537,9 @@ static int __maybe_unused s3_pci_resume(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
vga_wseq(par->state.vgabase, 0x08, 0x06);
|
||||
svga_wseq_mask(par->state.vgabase, 0x18, 0x00, 0x20);
|
||||
svga_wseq_mask(par->state.vgabase, 0x14, 0x00, 0x01);
|
||||
s3fb_set_par(info);
|
||||
fb_set_suspend(info, 0);
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ struct simplefb_par {
|
||||
|
||||
static void simplefb_clocks_destroy(struct simplefb_par *par);
|
||||
static void simplefb_regulators_destroy(struct simplefb_par *par);
|
||||
static void simplefb_detach_genpds(void *res);
|
||||
|
||||
/*
|
||||
* fb_ops.fb_destroy is called by the last put_fb_info() call at the end
|
||||
@@ -105,6 +106,7 @@ static void simplefb_destroy(struct fb_info *info)
|
||||
|
||||
simplefb_regulators_destroy(info->par);
|
||||
simplefb_clocks_destroy(info->par);
|
||||
simplefb_detach_genpds(info->par);
|
||||
if (info->screen_base)
|
||||
iounmap(info->screen_base);
|
||||
|
||||
@@ -445,13 +447,14 @@ static void simplefb_detach_genpds(void *res)
|
||||
if (!IS_ERR_OR_NULL(par->genpds[i]))
|
||||
dev_pm_domain_detach(par->genpds[i], true);
|
||||
}
|
||||
par->num_genpds = 0;
|
||||
}
|
||||
|
||||
static int simplefb_attach_genpds(struct simplefb_par *par,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
unsigned int i;
|
||||
unsigned int i, num_genpds;
|
||||
int err;
|
||||
|
||||
err = of_count_phandle_with_args(dev->of_node, "power-domains",
|
||||
@@ -465,26 +468,35 @@ static int simplefb_attach_genpds(struct simplefb_par *par,
|
||||
return err;
|
||||
}
|
||||
|
||||
par->num_genpds = err;
|
||||
num_genpds = err;
|
||||
|
||||
/*
|
||||
* Single power-domain devices are handled by the driver core, so
|
||||
* nothing to do here.
|
||||
*/
|
||||
if (par->num_genpds <= 1)
|
||||
if (num_genpds <= 1) {
|
||||
par->num_genpds = num_genpds;
|
||||
return 0;
|
||||
}
|
||||
|
||||
par->genpds = devm_kcalloc(dev, par->num_genpds, sizeof(*par->genpds),
|
||||
par->genpds = devm_kcalloc(dev, num_genpds, sizeof(*par->genpds),
|
||||
GFP_KERNEL);
|
||||
if (!par->genpds)
|
||||
return -ENOMEM;
|
||||
|
||||
par->genpd_links = devm_kcalloc(dev, par->num_genpds,
|
||||
par->genpd_links = devm_kcalloc(dev, num_genpds,
|
||||
sizeof(*par->genpd_links),
|
||||
GFP_KERNEL);
|
||||
if (!par->genpd_links)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Set par->num_genpds only after genpds and genpd_links are allocated
|
||||
* to exit early from simplefb_detach_genpds() without full
|
||||
* initialisation.
|
||||
*/
|
||||
par->num_genpds = num_genpds;
|
||||
|
||||
for (i = 0; i < par->num_genpds; i++) {
|
||||
par->genpds[i] = dev_pm_domain_attach_by_id(dev, i);
|
||||
if (IS_ERR(par->genpds[i])) {
|
||||
@@ -506,9 +518,10 @@ static int simplefb_attach_genpds(struct simplefb_par *par,
|
||||
dev_warn(dev, "failed to link power-domain %u\n", i);
|
||||
}
|
||||
|
||||
return devm_add_action_or_reset(dev, simplefb_detach_genpds, par);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static void simplefb_detach_genpds(void *res) { }
|
||||
static int simplefb_attach_genpds(struct simplefb_par *par,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
@@ -622,18 +635,20 @@ static int simplefb_probe(struct platform_device *pdev)
|
||||
ret = devm_aperture_acquire_for_platform_device(pdev, par->base, par->size);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Unable to acquire aperture: %d\n", ret);
|
||||
goto error_regulators;
|
||||
goto error_genpds;
|
||||
}
|
||||
ret = register_framebuffer(info);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
|
||||
goto error_regulators;
|
||||
goto error_genpds;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
|
||||
|
||||
return 0;
|
||||
|
||||
error_genpds:
|
||||
simplefb_detach_genpds(par);
|
||||
error_regulators:
|
||||
simplefb_regulators_destroy(par);
|
||||
error_clocks:
|
||||
|
||||
@@ -390,7 +390,7 @@ static int xenfb_probe(struct xenbus_device *dev,
|
||||
|
||||
info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
|
||||
info->gfns = vmalloc(array_size(sizeof(unsigned long), info->nr_pages));
|
||||
info->gfns = vmalloc_array(info->nr_pages, sizeof(unsigned long));
|
||||
if (!info->gfns)
|
||||
goto error_nomem;
|
||||
|
||||
|
||||
@@ -433,7 +433,8 @@ static int iomap_dio_bio_iter(struct iomap_iter *iter, struct iomap_dio *dio)
|
||||
bio->bi_private = dio;
|
||||
bio->bi_end_io = iomap_dio_bio_end_io;
|
||||
|
||||
ret = bio_iov_iter_get_bdev_pages(bio, dio->submit.iter, iomap->bdev);
|
||||
ret = bio_iov_iter_get_pages(bio, dio->submit.iter,
|
||||
bdev_logical_block_size(iomap->bdev) - 1);
|
||||
if (unlikely(ret)) {
|
||||
/*
|
||||
* We have to stop part way through an IO. We must fall
|
||||
|
||||
+1
-6
@@ -446,14 +446,9 @@ int submit_bio_wait(struct bio *bio);
|
||||
int bdev_rw_virt(struct block_device *bdev, sector_t sector, void *data,
|
||||
size_t len, enum req_op op);
|
||||
|
||||
int bio_iov_iter_get_pages_aligned(struct bio *bio, struct iov_iter *iter,
|
||||
int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter,
|
||||
unsigned len_align_mask);
|
||||
|
||||
static inline int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
|
||||
{
|
||||
return bio_iov_iter_get_pages_aligned(bio, iter, 0);
|
||||
}
|
||||
|
||||
void bio_iov_bvec_set(struct bio *bio, const struct iov_iter *iter);
|
||||
void __bio_release_pages(struct bio *bio, bool mark_dirty);
|
||||
extern void bio_set_pages_dirty(struct bio *bio);
|
||||
|
||||
@@ -1873,13 +1873,6 @@ static inline int bio_split_rw_at(struct bio *bio,
|
||||
return bio_split_io_at(bio, lim, segs, max_bytes, lim->dma_alignment);
|
||||
}
|
||||
|
||||
static inline int bio_iov_iter_get_bdev_pages(struct bio *bio,
|
||||
struct iov_iter *iter, struct block_device *bdev)
|
||||
{
|
||||
return bio_iov_iter_get_pages_aligned(bio, iter,
|
||||
bdev_logical_block_size(bdev) - 1);
|
||||
}
|
||||
|
||||
#define DEFINE_IO_COMP_BATCH(name) struct io_comp_batch name = { }
|
||||
|
||||
#endif /* _LINUX_BLKDEV_H */
|
||||
@@ -71,7 +71,7 @@ struct i2c_algo_pca_data {
|
||||
void *data; /* private low level data */
|
||||
void (*write_byte) (void *data, int reg, int val);
|
||||
int (*read_byte) (void *data, int reg);
|
||||
int (*wait_for_completion) (void *data);
|
||||
int (*wait_for_completion_cb) (void *data);
|
||||
void (*reset_chip) (void *data);
|
||||
/* For PCA9564, use one of the predefined frequencies:
|
||||
* 330000, 288000, 217000, 146000, 88000, 59000, 44000, 36000
|
||||
|
||||
@@ -17,8 +17,8 @@ struct disk_stats {
|
||||
/*
|
||||
* Macros to operate on percpu disk statistics:
|
||||
*
|
||||
* {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters and should
|
||||
* be called between disk_stat_lock() and disk_stat_unlock().
|
||||
* part_stat_{add|sub|inc|dec}() modify the stat counters and should
|
||||
* be called between part_stat_lock() and part_stat_unlock().
|
||||
*
|
||||
* part_stat_read() can be called at any time.
|
||||
*/
|
||||
|
||||
+3
-2
@@ -228,10 +228,11 @@ enum tpm2_timeouts {
|
||||
TPM2_TIMEOUT_B = 4000,
|
||||
TPM2_TIMEOUT_C = 200,
|
||||
TPM2_TIMEOUT_D = 30,
|
||||
};
|
||||
|
||||
enum tpm2_durations {
|
||||
TPM2_DURATION_SHORT = 20,
|
||||
TPM2_DURATION_MEDIUM = 750,
|
||||
TPM2_DURATION_LONG = 2000,
|
||||
TPM2_DURATION_LONG_LONG = 300000,
|
||||
TPM2_DURATION_DEFAULT = 120000,
|
||||
};
|
||||
|
||||
|
||||
@@ -404,7 +404,7 @@ enum io_uring_op {
|
||||
* will be contiguous from the starting buffer ID.
|
||||
*
|
||||
* IORING_SEND_VECTORIZED If set, SEND[_ZC] will take a pointer to a io_vec
|
||||
* to allow vectorized send operations.
|
||||
* to allow vectorized send operations.
|
||||
*/
|
||||
#define IORING_RECVSEND_POLL_FIRST (1U << 0)
|
||||
#define IORING_RECV_MULTISHOT (1U << 1)
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
*
|
||||
* Also see the examples in the liburing library:
|
||||
*
|
||||
* git://git.kernel.dk/liburing
|
||||
* git://git.kernel.org/pub/scm/linux/kernel/git/axboe/liburing.git
|
||||
*
|
||||
* io_uring also uses READ/WRITE_ONCE() for _any_ store or load that happens
|
||||
* from data shared between the kernel and application. This is done both
|
||||
|
||||
+2
-1
@@ -230,13 +230,14 @@ static int io_waitid_wait(struct wait_queue_entry *wait, unsigned mode,
|
||||
if (!pid_child_should_wake(wo, p))
|
||||
return 0;
|
||||
|
||||
list_del_init(&wait->entry);
|
||||
|
||||
/* cancel is in progress */
|
||||
if (atomic_fetch_inc(&iw->refs) & IO_WAITID_REF_MASK)
|
||||
return 1;
|
||||
|
||||
req->io_task_work.func = io_waitid_cb;
|
||||
io_req_task_work_add(req);
|
||||
list_del_init(&wait->entry);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1079,6 +1079,7 @@ static ssize_t io_copy_page(struct io_copy_cache *cc, struct page *src_page,
|
||||
|
||||
cc->size -= n;
|
||||
cc->offset += n;
|
||||
src_offset += n;
|
||||
len -= n;
|
||||
copied += n;
|
||||
}
|
||||
@@ -1236,12 +1237,16 @@ io_zcrx_recv_skb(read_descriptor_t *desc, struct sk_buff *skb,
|
||||
|
||||
end = start + frag_iter->len;
|
||||
if (offset < end) {
|
||||
size_t count;
|
||||
|
||||
copy = end - offset;
|
||||
if (copy > len)
|
||||
copy = len;
|
||||
|
||||
off = offset - start;
|
||||
count = desc->count;
|
||||
ret = io_zcrx_recv_skb(desc, frag_iter, off, copy);
|
||||
desc->count = count;
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -1549,6 +1549,7 @@ static const struct snd_pci_quirk force_connect_list[] = {
|
||||
SND_PCI_QUIRK(0x103c, 0x83e2, "HP EliteDesk 800 G4", 1),
|
||||
SND_PCI_QUIRK(0x103c, 0x83ef, "HP MP9 G4 Retail System AMS", 1),
|
||||
SND_PCI_QUIRK(0x103c, 0x845a, "HP EliteDesk 800 G4 DM 65W", 1),
|
||||
SND_PCI_QUIRK(0x103c, 0x83f3, "HP ProDesk 400", 1),
|
||||
SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1),
|
||||
SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1),
|
||||
SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1),
|
||||
|
||||
@@ -3735,6 +3735,7 @@ enum {
|
||||
ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC,
|
||||
ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1,
|
||||
ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC,
|
||||
ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK,
|
||||
};
|
||||
|
||||
/* A special fixup for Lenovo C940 and Yoga Duet 7;
|
||||
@@ -6164,6 +6165,14 @@ static const struct hda_fixup alc269_fixups[] = {
|
||||
.chained = true,
|
||||
.chain_id = ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE,
|
||||
},
|
||||
[ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK] = {
|
||||
.type = HDA_FIXUP_PINS,
|
||||
.v.pins = (const struct hda_pintbl[]) {
|
||||
{ 0x17, 0x90170151 }, /* Internal Speaker LFE */
|
||||
{ 0x1e, 0x90170150 }, /* Internal Speaker */
|
||||
{ }
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static const struct hda_quirk alc269_fixup_tbl[] = {
|
||||
@@ -6718,6 +6727,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
|
||||
SND_PCI_QUIRK(0x1043, 0x1533, "ASUS GV302XA/XJ/XQ/XU/XV/XI", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301VV/VQ/VU/VJ/VA/VC/VE/VVC/VQC/VUC/VJC/VEC/VCC", ALC285_FIXUP_ASUS_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1652, "ASUS ROG Zephyrus Do 15 SE", ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK),
|
||||
SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
|
||||
SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1683, "ASUS UM3402YAR", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
|
||||
@@ -474,6 +474,12 @@ static void tasdevice_dspfw_init(void *context)
|
||||
if (tas_priv->fmw->nr_configurations > 0)
|
||||
tas_priv->cur_conf = 0;
|
||||
|
||||
/* Init common setting for different audio profiles */
|
||||
if (tas_priv->rcabin.init_profile_id >= 0)
|
||||
tasdevice_select_cfg_blk(tas_priv,
|
||||
tas_priv->rcabin.init_profile_id,
|
||||
TASDEVICE_BIN_BLK_PRE_POWER_UP);
|
||||
|
||||
/* If calibrated data occurs error, dsp will still works with default
|
||||
* calibrated data inside algo.
|
||||
*/
|
||||
@@ -770,6 +776,12 @@ static int tas2781_system_resume(struct device *dev)
|
||||
tasdevice_reset(tas_hda->priv);
|
||||
tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
|
||||
|
||||
/* Init common setting for different audio profiles */
|
||||
if (tas_hda->priv->rcabin.init_profile_id >= 0)
|
||||
tasdevice_select_cfg_blk(tas_hda->priv,
|
||||
tas_hda->priv->rcabin.init_profile_id,
|
||||
TASDEVICE_BIN_BLK_PRE_POWER_UP);
|
||||
|
||||
if (tas_hda->priv->playback_started)
|
||||
tasdevice_tuning_switch(tas_hda->priv, 0);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ static int rt722_sdca_mbq_size(struct device *dev, unsigned int reg)
|
||||
switch (reg) {
|
||||
case 0x2f01 ... 0x2f0a:
|
||||
case 0x2f35 ... 0x2f36:
|
||||
case 0x2f50:
|
||||
case 0x2f50 ... 0x2f52:
|
||||
case 0x2f54:
|
||||
case 0x2f58 ... 0x2f5d:
|
||||
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0):
|
||||
|
||||
@@ -1378,6 +1378,9 @@ static void rt722_sdca_dmic_preset(struct rt722_sdca_priv *rt722)
|
||||
/* PHYtiming TDZ/TZD control */
|
||||
regmap_write(rt722->regmap, 0x2f03, 0x06);
|
||||
|
||||
if (rt722->hw_vid == RT722_VB)
|
||||
regmap_write(rt722->regmap, 0x2f52, 0x00);
|
||||
|
||||
/* clear flag */
|
||||
regmap_write(rt722->regmap,
|
||||
SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0),
|
||||
@@ -1415,6 +1418,9 @@ static void rt722_sdca_amp_preset(struct rt722_sdca_priv *rt722)
|
||||
SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23,
|
||||
RT722_SDCA_CTL_VENDOR_DEF, CH_08), 0x04);
|
||||
|
||||
if (rt722->hw_vid == RT722_VB)
|
||||
regmap_write(rt722->regmap, 0x2f54, 0x00);
|
||||
|
||||
/* clear flag */
|
||||
regmap_write(rt722->regmap,
|
||||
SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0),
|
||||
@@ -1506,6 +1512,9 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722)
|
||||
rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_DIGITAL_MISC_CTRL4,
|
||||
0x0010);
|
||||
|
||||
if (rt722->hw_vid == RT722_VB)
|
||||
regmap_write(rt722->regmap, 0x2f51, 0x00);
|
||||
|
||||
/* clear flag */
|
||||
regmap_write(rt722->regmap,
|
||||
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0),
|
||||
@@ -1516,6 +1525,7 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722)
|
||||
int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
{
|
||||
struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev);
|
||||
unsigned int val;
|
||||
|
||||
rt722->disable_irq = false;
|
||||
|
||||
@@ -1545,6 +1555,10 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
|
||||
pm_runtime_get_noresume(&slave->dev);
|
||||
|
||||
rt722_sdca_index_read(rt722, RT722_VENDOR_REG, RT722_JD_PRODUCT_NUM, &val);
|
||||
rt722->hw_vid = (val & 0x0f00) >> 8;
|
||||
dev_dbg(&slave->dev, "%s hw_vid=0x%x\n", __func__, rt722->hw_vid);
|
||||
|
||||
rt722_sdca_dmic_preset(rt722);
|
||||
rt722_sdca_amp_preset(rt722);
|
||||
rt722_sdca_jack_preset(rt722);
|
||||
|
||||
@@ -39,6 +39,7 @@ struct rt722_sdca_priv {
|
||||
/* For DMIC */
|
||||
bool fu1e_dapm_mute;
|
||||
bool fu1e_mixer_mute[4];
|
||||
int hw_vid;
|
||||
};
|
||||
|
||||
struct rt722_sdca_dmic_kctrl_priv {
|
||||
@@ -233,6 +234,11 @@ enum rt722_sdca_jd_src {
|
||||
RT722_JD1,
|
||||
};
|
||||
|
||||
enum rt722_sdca_version {
|
||||
RT722_VA,
|
||||
RT722_VB,
|
||||
};
|
||||
|
||||
int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave);
|
||||
int rt722_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave);
|
||||
int rt722_sdca_index_write(struct rt722_sdca_priv *rt722,
|
||||
|
||||
@@ -236,8 +236,12 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
inv == SND_SOC_DAIFMT_IB_IF)
|
||||
val |= AIU_CLK_CTRL_LRCLK_INVERT;
|
||||
|
||||
if (inv == SND_SOC_DAIFMT_IB_NF ||
|
||||
inv == SND_SOC_DAIFMT_IB_IF)
|
||||
/*
|
||||
* The SoC changes data on the rising edge of the bitclock
|
||||
* so an inversion of the bitclock is required in normal mode
|
||||
*/
|
||||
if (inv == SND_SOC_DAIFMT_NB_NF ||
|
||||
inv == SND_SOC_DAIFMT_NB_IF)
|
||||
val |= AIU_CLK_CTRL_AOCLK_INVERT;
|
||||
|
||||
/* Signal skew */
|
||||
@@ -328,4 +332,3 @@ const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = {
|
||||
.startup = aiu_encoder_i2s_startup,
|
||||
.shutdown = aiu_encoder_i2s_shutdown,
|
||||
};
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#define SDnFMT_BITS(x) ((x) << 4)
|
||||
#define SDnFMT_CHAN(x) ((x) << 0)
|
||||
|
||||
#define HDA_MAX_PERIOD_TIME_HEADROOM 10
|
||||
|
||||
static bool hda_always_enable_dmi_l1;
|
||||
module_param_named(always_enable_dmi_l1, hda_always_enable_dmi_l1, bool, 0444);
|
||||
MODULE_PARM_DESC(always_enable_dmi_l1, "SOF HDA always enable DMI l1");
|
||||
@@ -291,19 +293,30 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
|
||||
* On playback start the DMA will transfer dsp_max_burst_size_in_ms
|
||||
* amount of data in one initial burst to fill up the host DMA buffer.
|
||||
* Consequent DMA burst sizes are shorter and their length can vary.
|
||||
* To make sure that userspace allocate large enough ALSA buffer we need
|
||||
* to place a constraint on the buffer time.
|
||||
* To avoid immediate xrun by the initial burst we need to place
|
||||
* constraint on the period size (via PERIOD_TIME) to cover the size of
|
||||
* the host buffer.
|
||||
* We need to add headroom of max 10ms as the firmware needs time to
|
||||
* settle to the 1ms pacing and initially it can run faster for few
|
||||
* internal periods.
|
||||
*
|
||||
* On capture the DMA will transfer 1ms chunks.
|
||||
*
|
||||
* Exact dsp_max_burst_size_in_ms constraint is racy, so set the
|
||||
* constraint to a minimum of 2x dsp_max_burst_size_in_ms.
|
||||
*/
|
||||
if (spcm->stream[direction].dsp_max_burst_size_in_ms)
|
||||
if (spcm->stream[direction].dsp_max_burst_size_in_ms) {
|
||||
unsigned int period_time = spcm->stream[direction].dsp_max_burst_size_in_ms;
|
||||
|
||||
/*
|
||||
* add headroom over the maximum burst size to cover the time
|
||||
* needed for the DMA pace to settle.
|
||||
* Limit the headroom time to HDA_MAX_PERIOD_TIME_HEADROOM
|
||||
*/
|
||||
period_time += min(period_time, HDA_MAX_PERIOD_TIME_HEADROOM);
|
||||
|
||||
snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||
SNDRV_PCM_HW_PARAM_BUFFER_TIME,
|
||||
spcm->stream[direction].dsp_max_burst_size_in_ms * USEC_PER_MSEC * 2,
|
||||
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
|
||||
period_time * USEC_PER_MSEC,
|
||||
UINT_MAX);
|
||||
}
|
||||
|
||||
/* binding pcm substream to hda stream */
|
||||
substream->runtime->private_data = &dsp_stream->hstream;
|
||||
|
||||
@@ -1129,10 +1129,35 @@ u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
|
||||
struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct hdac_stream *hstream = substream->runtime->private_data;
|
||||
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_pcm_runtime *be_rtd = NULL;
|
||||
struct hdac_ext_stream *hext_stream;
|
||||
struct snd_soc_dai *cpu_dai;
|
||||
struct snd_soc_dpcm *dpcm;
|
||||
u32 llp_l, llp_u;
|
||||
|
||||
/*
|
||||
* The LLP needs to be read from the Link DMA used for this FE as it is
|
||||
* allowed to use any combination of Link and Host channels
|
||||
*/
|
||||
for_each_dpcm_be(rtd, substream->stream, dpcm) {
|
||||
if (dpcm->fe != rtd)
|
||||
continue;
|
||||
|
||||
be_rtd = dpcm->be;
|
||||
}
|
||||
|
||||
if (!be_rtd)
|
||||
return 0;
|
||||
|
||||
cpu_dai = snd_soc_rtd_to_cpu(be_rtd, 0);
|
||||
if (!cpu_dai)
|
||||
return 0;
|
||||
|
||||
hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
|
||||
if (!hext_stream)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The pplc_addr have been calculated during probe in
|
||||
* hda_dsp_stream_init():
|
||||
|
||||
@@ -2473,11 +2473,6 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* free all the scheduler widgets now */
|
||||
ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Tear down all pipelines associated with PCMs that did not get suspended
|
||||
* and unset the prepare flag so that they can be set up again during resume.
|
||||
@@ -2493,6 +2488,11 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
|
||||
}
|
||||
}
|
||||
|
||||
/* free all the scheduler widgets now. This will also power down the secondary cores */
|
||||
ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
list_for_each_entry(sroute, &sdev->route_list, list)
|
||||
sroute->setup = false;
|
||||
|
||||
|
||||
+80
-24
@@ -19,12 +19,14 @@
|
||||
* struct sof_ipc4_timestamp_info - IPC4 timestamp info
|
||||
* @host_copier: the host copier of the pcm stream
|
||||
* @dai_copier: the dai copier of the pcm stream
|
||||
* @stream_start_offset: reported by fw in memory window (converted to frames)
|
||||
* @stream_end_offset: reported by fw in memory window (converted to frames)
|
||||
* @stream_start_offset: reported by fw in memory window (converted to
|
||||
* frames at host_copier sampling rate)
|
||||
* @stream_end_offset: reported by fw in memory window (converted to
|
||||
* frames at host_copier sampling rate)
|
||||
* @llp_offset: llp offset in memory window
|
||||
* @boundary: wrap boundary should be used for the LLP frame counter
|
||||
* @delay: Calculated and stored in pointer callback. The stored value is
|
||||
* returned in the delay callback.
|
||||
* returned in the delay callback. Expressed in frames at host copier
|
||||
* sampling rate.
|
||||
*/
|
||||
struct sof_ipc4_timestamp_info {
|
||||
struct sof_ipc4_copier *host_copier;
|
||||
@@ -33,7 +35,6 @@ struct sof_ipc4_timestamp_info {
|
||||
u64 stream_end_offset;
|
||||
u32 llp_offset;
|
||||
|
||||
u64 boundary;
|
||||
snd_pcm_sframes_t delay;
|
||||
};
|
||||
|
||||
@@ -48,6 +49,18 @@ struct sof_ipc4_pcm_stream_priv {
|
||||
bool chain_dma_allocated;
|
||||
};
|
||||
|
||||
/*
|
||||
* Modulus to use to compare host and link position counters. The sampling
|
||||
* rates may be different, so the raw hardware counters will wrap
|
||||
* around at different times. To calculate differences, use
|
||||
* DELAY_BOUNDARY as a common modulus. This value must be smaller than
|
||||
* the wrap-around point of any hardware counter, and larger than any
|
||||
* valid delay measurement.
|
||||
*/
|
||||
#define DELAY_BOUNDARY U32_MAX
|
||||
|
||||
#define DELAY_MAX (DELAY_BOUNDARY >> 1)
|
||||
|
||||
static inline struct sof_ipc4_timestamp_info *
|
||||
sof_ipc4_sps_to_time_info(struct snd_sof_pcm_stream *sps)
|
||||
{
|
||||
@@ -1049,6 +1062,35 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 sof_ipc4_frames_dai_to_host(struct sof_ipc4_timestamp_info *time_info, u64 value)
|
||||
{
|
||||
u64 dai_rate, host_rate;
|
||||
|
||||
if (!time_info->dai_copier || !time_info->host_copier)
|
||||
return value;
|
||||
|
||||
/*
|
||||
* copiers do not change sampling rate, so we can use the
|
||||
* out_format independently of stream direction
|
||||
*/
|
||||
dai_rate = time_info->dai_copier->data.out_format.sampling_frequency;
|
||||
host_rate = time_info->host_copier->data.out_format.sampling_frequency;
|
||||
|
||||
if (!dai_rate || !host_rate || dai_rate == host_rate)
|
||||
return value;
|
||||
|
||||
/* take care not to overflow u64, rates can be up to 768000 */
|
||||
if (value > U32_MAX) {
|
||||
value = div64_u64(value, dai_rate);
|
||||
value *= host_rate;
|
||||
} else {
|
||||
value *= host_rate;
|
||||
value = div64_u64(value, dai_rate);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_sof_pcm_stream *sps,
|
||||
@@ -1068,7 +1110,7 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
|
||||
return -EINVAL;
|
||||
} else if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_CHAIN_DMA_NODE_ID) {
|
||||
/*
|
||||
* While the firmware does not supports time_info reporting for
|
||||
* While the firmware does not support time_info reporting for
|
||||
* streams using ChainDMA, it is granted that ChainDMA can only
|
||||
* be used on Host+Link pairs where the link position is
|
||||
* accessible from the host side.
|
||||
@@ -1076,10 +1118,16 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
|
||||
* Enable delay calculation in case of ChainDMA via host
|
||||
* accessible registers.
|
||||
*
|
||||
* The ChainDMA uses 2x 1ms ping-pong buffer, dai side starts
|
||||
* when 1ms data is available
|
||||
* The ChainDMA prefills the link DMA with a preamble
|
||||
* of zero samples. Set the stream start offset based
|
||||
* on size of the preamble (driver provided fifo size
|
||||
* multiplied by 2.5). We add 1ms of margin as the FW
|
||||
* will align the buffer size to DMA hardware
|
||||
* alignment that is not known to host.
|
||||
*/
|
||||
time_info->stream_start_offset = substream->runtime->rate / MSEC_PER_SEC;
|
||||
int pre_ms = SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS * 5 / 2 + 1;
|
||||
|
||||
time_info->stream_start_offset = pre_ms * substream->runtime->rate / MSEC_PER_SEC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1099,14 +1147,13 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
|
||||
time_info->stream_end_offset = ppl_reg.stream_end_offset;
|
||||
do_div(time_info->stream_end_offset, dai_sample_size);
|
||||
|
||||
/* convert to host frame time */
|
||||
time_info->stream_start_offset =
|
||||
sof_ipc4_frames_dai_to_host(time_info, time_info->stream_start_offset);
|
||||
time_info->stream_end_offset =
|
||||
sof_ipc4_frames_dai_to_host(time_info, time_info->stream_end_offset);
|
||||
|
||||
out:
|
||||
/*
|
||||
* Calculate the wrap boundary need to be used for delay calculation
|
||||
* The host counter is in bytes, it will wrap earlier than the frames
|
||||
* based link counter.
|
||||
*/
|
||||
time_info->boundary = div64_u64(~((u64)0),
|
||||
frames_to_bytes(substream->runtime, 1));
|
||||
/* Initialize the delay value to 0 (no delay) */
|
||||
time_info->delay = 0;
|
||||
|
||||
@@ -1149,6 +1196,8 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
|
||||
|
||||
/* For delay calculation we need the host counter */
|
||||
host_cnt = snd_sof_pcm_get_host_byte_counter(sdev, component, substream);
|
||||
|
||||
/* Store the original value to host_ptr */
|
||||
host_ptr = host_cnt;
|
||||
|
||||
/* convert the host_cnt to frames */
|
||||
@@ -1167,6 +1216,8 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
|
||||
sof_mailbox_read(sdev, time_info->llp_offset, &llp, sizeof(llp));
|
||||
dai_cnt = ((u64)llp.reading.llp_u << 32) | llp.reading.llp_l;
|
||||
}
|
||||
|
||||
dai_cnt = sof_ipc4_frames_dai_to_host(time_info, dai_cnt);
|
||||
dai_cnt += time_info->stream_end_offset;
|
||||
|
||||
/* In two cases dai dma counter is not accurate
|
||||
@@ -1200,8 +1251,9 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
|
||||
dai_cnt -= time_info->stream_start_offset;
|
||||
}
|
||||
|
||||
/* Wrap the dai counter at the boundary where the host counter wraps */
|
||||
div64_u64_rem(dai_cnt, time_info->boundary, &dai_cnt);
|
||||
/* Convert to a common base before comparisons */
|
||||
dai_cnt &= DELAY_BOUNDARY;
|
||||
host_cnt &= DELAY_BOUNDARY;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
head_cnt = host_cnt;
|
||||
@@ -1211,14 +1263,18 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
|
||||
tail_cnt = host_cnt;
|
||||
}
|
||||
|
||||
if (head_cnt < tail_cnt) {
|
||||
time_info->delay = time_info->boundary - tail_cnt + head_cnt;
|
||||
goto out;
|
||||
if (unlikely(head_cnt < tail_cnt))
|
||||
time_info->delay = DELAY_BOUNDARY - tail_cnt + head_cnt;
|
||||
else
|
||||
time_info->delay = head_cnt - tail_cnt;
|
||||
|
||||
if (time_info->delay > DELAY_MAX) {
|
||||
spcm_dbg_ratelimited(spcm, substream->stream,
|
||||
"inaccurate delay, host %llu dai_cnt %llu",
|
||||
host_cnt, dai_cnt);
|
||||
time_info->delay = 0;
|
||||
}
|
||||
|
||||
time_info->delay = head_cnt - tail_cnt;
|
||||
|
||||
out:
|
||||
/*
|
||||
* Convert the host byte counter to PCM pointer which wraps in buffer
|
||||
* and it is in frames
|
||||
|
||||
@@ -33,7 +33,6 @@ MODULE_PARM_DESC(ipc4_ignore_cpc,
|
||||
|
||||
#define SOF_IPC4_GAIN_PARAM_ID 0
|
||||
#define SOF_IPC4_TPLG_ABI_SIZE 6
|
||||
#define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2
|
||||
|
||||
static DEFINE_IDA(alh_group_ida);
|
||||
static DEFINE_IDA(pipeline_ida);
|
||||
@@ -666,8 +665,13 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
|
||||
swidget->tuples,
|
||||
swidget->num_tuples, sizeof(u32), 1);
|
||||
/* Set default DMA buffer size if it is not specified in topology */
|
||||
if (!sps->dsp_max_burst_size_in_ms)
|
||||
sps->dsp_max_burst_size_in_ms = SOF_IPC4_MIN_DMA_BUFFER_SIZE;
|
||||
if (!sps->dsp_max_burst_size_in_ms) {
|
||||
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
|
||||
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
|
||||
|
||||
sps->dsp_max_burst_size_in_ms = pipeline->use_chain_dma ?
|
||||
SOF_IPC4_CHAIN_DMA_BUFFER_SIZE : SOF_IPC4_MIN_DMA_BUFFER_SIZE;
|
||||
}
|
||||
} else {
|
||||
/* Capture data is copied from DSP to host in 1ms bursts */
|
||||
spcm->stream[dir].dsp_max_burst_size_in_ms = 1;
|
||||
|
||||
@@ -70,8 +70,11 @@
|
||||
#define SOF_IPC4_CHAIN_DMA_NODE_ID 0x7fffffff
|
||||
#define SOF_IPC4_INVALID_NODE_ID 0xffffffff
|
||||
|
||||
/* FW requires minimum 2ms DMA buffer size */
|
||||
#define SOF_IPC4_MIN_DMA_BUFFER_SIZE 2
|
||||
/* FW requires minimum 4ms DMA buffer size */
|
||||
#define SOF_IPC4_MIN_DMA_BUFFER_SIZE 4
|
||||
|
||||
/* ChainDMA in fw uses 5ms DMA buffer */
|
||||
#define SOF_IPC4_CHAIN_DMA_BUFFER_SIZE 5
|
||||
|
||||
/*
|
||||
* The base of multi-gateways. Multi-gateways addressing starts from
|
||||
@@ -263,6 +266,8 @@ struct sof_ipc4_dma_stream_ch_map {
|
||||
#define SOF_IPC4_DMA_METHOD_HDA 1
|
||||
#define SOF_IPC4_DMA_METHOD_GPDMA 2 /* defined for consistency but not used */
|
||||
|
||||
#define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2
|
||||
|
||||
/**
|
||||
* struct sof_ipc4_dma_config: DMA configuration
|
||||
* @dma_method: HDAudio or GPDMA
|
||||
|
||||
@@ -629,6 +629,11 @@ void snd_sof_pcm_init_elapsed_work(struct work_struct *work);
|
||||
(__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
#define spcm_dbg_ratelimited(__spcm, __dir, __fmt, ...) \
|
||||
dev_dbg_ratelimited((__spcm)->scomp->dev, "pcm%u (%s), dir %d: " __fmt, \
|
||||
(__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
#define spcm_err(__spcm, __dir, __fmt, ...) \
|
||||
dev_err((__spcm)->scomp->dev, "%s: pcm%u (%s), dir %d: " __fmt, \
|
||||
__func__, (__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \
|
||||
|
||||
+3
-6
@@ -641,12 +641,9 @@ static int fcp_ioctl_set_meter_map(struct usb_mixer_interface *mixer,
|
||||
return -EINVAL;
|
||||
|
||||
/* Allocate and copy the map data */
|
||||
tmp_map = kmalloc_array(map.map_size, sizeof(s16), GFP_KERNEL);
|
||||
if (!tmp_map)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(tmp_map, arg->map, map.map_size * sizeof(s16)))
|
||||
return -EFAULT;
|
||||
tmp_map = memdup_array_user(arg->map, map.map_size, sizeof(s16));
|
||||
if (IS_ERR(tmp_map))
|
||||
return PTR_ERR(tmp_map);
|
||||
|
||||
err = validate_meter_map(tmp_map, map.map_size, map.meter_slots);
|
||||
if (err < 0)
|
||||
|
||||
Reference in new issue
Block a user