Merge e92b99ae82 ("Merge tag 'trace-v6.9-rc6-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace") into android-mainline
Steps on the way to v6.9 Signed-off-by: Lee Jones <joneslee@google.com> Change-Id: I9ccf65cffe660b3bb134fa158492a1a5caf1a43c
This commit is contained in:
@@ -20,6 +20,11 @@ Optional properties:
|
||||
a GPIO spec for the external headphone detect pin. If jd-mode = 0,
|
||||
we will get the JD status by getting the value of hp-detect-gpios.
|
||||
|
||||
- cbj-sleeve-gpios:
|
||||
a GPIO spec to control the external combo jack circuit to tie the sleeve/ring2
|
||||
contacts to the ground or floating. It could avoid some electric noise from the
|
||||
active speaker jacks.
|
||||
|
||||
- realtek,in2-differential
|
||||
Boolean. Indicate MIC2 input are differential, rather than single-ended.
|
||||
|
||||
@@ -68,6 +73,7 @@ codec: rt5650@1a {
|
||||
compatible = "realtek,rt5650";
|
||||
reg = <0x1a>;
|
||||
hp-detect-gpios = <&gpio 19 0>;
|
||||
cbj-sleeve-gpios = <&gpio 20 0>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
|
||||
realtek,dmic-en = "true";
|
||||
|
||||
@@ -219,13 +219,21 @@ static __read_mostly unsigned int cpuid_leaf5_edx_val;
|
||||
static void xen_cpuid(unsigned int *ax, unsigned int *bx,
|
||||
unsigned int *cx, unsigned int *dx)
|
||||
{
|
||||
unsigned maskebx = ~0;
|
||||
unsigned int maskebx = ~0;
|
||||
unsigned int or_ebx = 0;
|
||||
|
||||
/*
|
||||
* Mask out inconvenient features, to try and disable as many
|
||||
* unsupported kernel subsystems as possible.
|
||||
*/
|
||||
switch (*ax) {
|
||||
case 0x1:
|
||||
/* Replace initial APIC ID in bits 24-31 of EBX. */
|
||||
/* See xen_pv_smp_config() for related topology preparations. */
|
||||
maskebx = 0x00ffffff;
|
||||
or_ebx = smp_processor_id() << 24;
|
||||
break;
|
||||
|
||||
case CPUID_MWAIT_LEAF:
|
||||
/* Synthesize the values.. */
|
||||
*ax = 0;
|
||||
@@ -248,6 +256,7 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
|
||||
: "0" (*ax), "2" (*cx));
|
||||
|
||||
*bx &= maskebx;
|
||||
*bx |= or_ebx;
|
||||
}
|
||||
|
||||
static bool __init xen_check_mwait(void)
|
||||
|
||||
@@ -154,9 +154,9 @@ static void __init xen_pv_smp_config(void)
|
||||
u32 apicid = 0;
|
||||
int i;
|
||||
|
||||
topology_register_boot_apic(apicid++);
|
||||
topology_register_boot_apic(apicid);
|
||||
|
||||
for (i = 1; i < nr_cpu_ids; i++)
|
||||
for (i = 0; i < nr_cpu_ids; i++)
|
||||
topology_register_apic(apicid++, CPU_ACPIID_INVALID, true);
|
||||
|
||||
/* Pretend to be a proper enumerated system */
|
||||
|
||||
@@ -2838,6 +2838,43 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_read);
|
||||
|
||||
/**
|
||||
* regmap_read_bypassed() - Read a value from a single register direct
|
||||
* from the device, bypassing the cache
|
||||
*
|
||||
* @map: Register map to read from
|
||||
* @reg: Register to be read from
|
||||
* @val: Pointer to store read value
|
||||
*
|
||||
* A value of zero will be returned on success, a negative errno will
|
||||
* be returned in error cases.
|
||||
*/
|
||||
int regmap_read_bypassed(struct regmap *map, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
int ret;
|
||||
bool bypass, cache_only;
|
||||
|
||||
if (!IS_ALIGNED(reg, map->reg_stride))
|
||||
return -EINVAL;
|
||||
|
||||
map->lock(map->lock_arg);
|
||||
|
||||
bypass = map->cache_bypass;
|
||||
cache_only = map->cache_only;
|
||||
map->cache_bypass = true;
|
||||
map->cache_only = false;
|
||||
|
||||
ret = _regmap_read(map, reg, val);
|
||||
|
||||
map->cache_bypass = bypass;
|
||||
map->cache_only = cache_only;
|
||||
|
||||
map->unlock(map->lock_arg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_read_bypassed);
|
||||
|
||||
/**
|
||||
* regmap_raw_read() - Read raw data from the device
|
||||
*
|
||||
|
||||
@@ -2177,7 +2177,8 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, struct io_uring_cmd *cmd)
|
||||
.max_hw_sectors = p->max_sectors,
|
||||
.chunk_sectors = p->chunk_sectors,
|
||||
.virt_boundary_mask = p->virt_boundary_mask,
|
||||
|
||||
.max_segments = USHRT_MAX,
|
||||
.max_segment_size = UINT_MAX,
|
||||
};
|
||||
struct gendisk *disk;
|
||||
int ret = -EINVAL;
|
||||
|
||||
@@ -768,6 +768,7 @@ static struct clk_smd_rpm *msm8976_clks[] = {
|
||||
|
||||
static const struct rpm_smd_clk_desc rpm_clk_msm8976 = {
|
||||
.clks = msm8976_clks,
|
||||
.num_clks = ARRAY_SIZE(msm8976_clks),
|
||||
.icc_clks = bimc_pcnoc_snoc_smmnoc_icc_clks,
|
||||
.num_icc_clks = ARRAY_SIZE(bimc_pcnoc_snoc_smmnoc_icc_clks),
|
||||
};
|
||||
|
||||
@@ -487,9 +487,14 @@ int gdsc_register(struct gdsc_desc *desc,
|
||||
if (!scs[i] || !scs[i]->supply)
|
||||
continue;
|
||||
|
||||
scs[i]->rsupply = devm_regulator_get(dev, scs[i]->supply);
|
||||
if (IS_ERR(scs[i]->rsupply))
|
||||
return PTR_ERR(scs[i]->rsupply);
|
||||
scs[i]->rsupply = devm_regulator_get_optional(dev, scs[i]->supply);
|
||||
if (IS_ERR(scs[i]->rsupply)) {
|
||||
ret = PTR_ERR(scs[i]->rsupply);
|
||||
if (ret != -ENODEV)
|
||||
return ret;
|
||||
|
||||
scs[i]->rsupply = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
data->num_domains = num;
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#define EXYNOS_CLKOUT_NR_CLKS 1
|
||||
#define EXYNOS_CLKOUT_PARENTS 32
|
||||
@@ -84,17 +84,24 @@ MODULE_DEVICE_TABLE(of, exynos_clkout_ids);
|
||||
static int exynos_clkout_match_parent_dev(struct device *dev, u32 *mux_mask)
|
||||
{
|
||||
const struct exynos_clkout_variant *variant;
|
||||
const struct of_device_id *match;
|
||||
|
||||
if (!dev->parent) {
|
||||
dev_err(dev, "not instantiated from MFD\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
variant = device_get_match_data(dev->parent);
|
||||
if (!variant) {
|
||||
/*
|
||||
* 'exynos_clkout_ids' arrays is not the ids array matched by
|
||||
* the dev->parent driver, so of_device_get_match_data() or
|
||||
* device_get_match_data() cannot be used here.
|
||||
*/
|
||||
match = of_match_device(exynos_clkout_ids, dev->parent);
|
||||
if (!match) {
|
||||
dev_err(dev, "cannot match parent device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
variant = match->data;
|
||||
|
||||
*mux_mask = variant->mux_mask;
|
||||
|
||||
|
||||
@@ -182,6 +182,8 @@ static struct ccu_nkm pll_mipi_clk = {
|
||||
&ccu_nkm_ops,
|
||||
CLK_SET_RATE_UNGATE | CLK_SET_RATE_PARENT),
|
||||
.features = CCU_FEATURE_CLOSEST_RATE,
|
||||
.min_rate = 500000000,
|
||||
.max_rate = 1400000000,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1181,11 +1181,18 @@ static const u32 usb2_clk_regs[] = {
|
||||
SUN50I_H6_USB3_CLK_REG,
|
||||
};
|
||||
|
||||
static struct ccu_mux_nb sun50i_h6_cpu_nb = {
|
||||
.common = &cpux_clk.common,
|
||||
.cm = &cpux_clk.mux,
|
||||
.delay_us = 1,
|
||||
.bypass_index = 0, /* index of 24 MHz oscillator */
|
||||
};
|
||||
|
||||
static int sun50i_h6_ccu_probe(struct platform_device *pdev)
|
||||
{
|
||||
void __iomem *reg;
|
||||
int i, ret;
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
reg = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(reg))
|
||||
@@ -1252,7 +1259,15 @@ static int sun50i_h6_ccu_probe(struct platform_device *pdev)
|
||||
val |= BIT(24);
|
||||
writel(val, reg + SUN50I_H6_HDMI_CEC_CLK_REG);
|
||||
|
||||
return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_h6_ccu_desc);
|
||||
ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_h6_ccu_desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Reparent CPU during PLL CPUX rate changes */
|
||||
ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
|
||||
&sun50i_h6_cpu_nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sun50i_h6_ccu_ids[] = {
|
||||
|
||||
@@ -44,6 +44,16 @@ bool ccu_is_better_rate(struct ccu_common *common,
|
||||
unsigned long current_rate,
|
||||
unsigned long best_rate)
|
||||
{
|
||||
unsigned long min_rate, max_rate;
|
||||
|
||||
clk_hw_get_rate_range(&common->hw, &min_rate, &max_rate);
|
||||
|
||||
if (current_rate > max_rate)
|
||||
return false;
|
||||
|
||||
if (current_rate < min_rate)
|
||||
return false;
|
||||
|
||||
if (common->features & CCU_FEATURE_CLOSEST_RATE)
|
||||
return abs(current_rate - target_rate) < abs(best_rate - target_rate);
|
||||
|
||||
@@ -122,6 +132,7 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
|
||||
|
||||
for (i = 0; i < desc->hw_clks->num ; i++) {
|
||||
struct clk_hw *hw = desc->hw_clks->hws[i];
|
||||
struct ccu_common *common = hw_to_ccu_common(hw);
|
||||
const char *name;
|
||||
|
||||
if (!hw)
|
||||
@@ -136,6 +147,14 @@ static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev,
|
||||
pr_err("Couldn't register clock %d - %s\n", i, name);
|
||||
goto err_clk_unreg;
|
||||
}
|
||||
|
||||
if (common->max_rate)
|
||||
clk_hw_set_rate_range(hw, common->min_rate,
|
||||
common->max_rate);
|
||||
else
|
||||
WARN(common->min_rate,
|
||||
"No max_rate, ignoring min_rate of clock %d - %s\n",
|
||||
i, name);
|
||||
}
|
||||
|
||||
ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
|
||||
|
||||
@@ -31,6 +31,9 @@ struct ccu_common {
|
||||
u16 lock_reg;
|
||||
u32 prediv;
|
||||
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
|
||||
unsigned long features;
|
||||
spinlock_t *lock;
|
||||
struct clk_hw hw;
|
||||
|
||||
+14
-1
@@ -2184,6 +2184,7 @@ static bool parent_port_is_cxl_root(struct cxl_port *port)
|
||||
int cxl_endpoint_get_perf_coordinates(struct cxl_port *port,
|
||||
struct access_coordinate *coord)
|
||||
{
|
||||
struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
|
||||
struct access_coordinate c[] = {
|
||||
{
|
||||
.read_bandwidth = UINT_MAX,
|
||||
@@ -2197,12 +2198,20 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port,
|
||||
struct cxl_port *iter = port;
|
||||
struct cxl_dport *dport;
|
||||
struct pci_dev *pdev;
|
||||
struct device *dev;
|
||||
unsigned int bw;
|
||||
bool is_cxl_root;
|
||||
|
||||
if (!is_cxl_endpoint(port))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Skip calculation for RCD. Expectation is HMAT already covers RCD case
|
||||
* since RCH does not support hotplug.
|
||||
*/
|
||||
if (cxlmd->cxlds->rcd)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Exit the loop when the parent port of the current iter port is cxl
|
||||
* root. The iterative loop starts at the endpoint and gathers the
|
||||
@@ -2232,8 +2241,12 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port,
|
||||
return -EINVAL;
|
||||
cxl_coordinates_combine(c, c, dport->coord);
|
||||
|
||||
dev = port->uport_dev->parent;
|
||||
if (!dev_is_pci(dev))
|
||||
return -ENODEV;
|
||||
|
||||
/* Get the calculated PCI paths bandwidth */
|
||||
pdev = to_pci_dev(port->uport_dev->parent);
|
||||
pdev = to_pci_dev(dev);
|
||||
bw = pcie_bandwidth_available(pdev, NULL, NULL, NULL);
|
||||
if (bw == 0)
|
||||
return -ENXIO;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/crash_dump.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <asm/unaccepted_memory.h>
|
||||
|
||||
/* Protects unaccepted memory bitmap and accepting_list */
|
||||
@@ -149,6 +150,9 @@ retry:
|
||||
}
|
||||
|
||||
list_del(&range.list);
|
||||
|
||||
touch_softlockup_watchdog();
|
||||
|
||||
spin_unlock_irqrestore(&unaccepted_memory_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -220,7 +220,7 @@ int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev,
|
||||
(kfd_mem_limit.ttm_mem_used + ttm_mem_needed >
|
||||
kfd_mem_limit.max_ttm_mem_limit) ||
|
||||
(adev && xcp_id >= 0 && adev->kfd.vram_used[xcp_id] + vram_needed >
|
||||
vram_size - reserved_for_pt)) {
|
||||
vram_size - reserved_for_pt - atomic64_read(&adev->vram_pin_size))) {
|
||||
ret = -ENOMEM;
|
||||
goto release;
|
||||
}
|
||||
|
||||
@@ -1243,14 +1243,18 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
|
||||
* amdgpu_bo_move_notify - notification about a memory move
|
||||
* @bo: pointer to a buffer object
|
||||
* @evict: if this move is evicting the buffer from the graphics address space
|
||||
* @new_mem: new resource for backing the BO
|
||||
*
|
||||
* Marks the corresponding &amdgpu_bo buffer object as invalid, also performs
|
||||
* bookkeeping.
|
||||
* TTM driver callback which is called when ttm moves a buffer.
|
||||
*/
|
||||
void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, bool evict)
|
||||
void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
|
||||
bool evict,
|
||||
struct ttm_resource *new_mem)
|
||||
{
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
|
||||
struct ttm_resource *old_mem = bo->resource;
|
||||
struct amdgpu_bo *abo;
|
||||
|
||||
if (!amdgpu_bo_is_amdgpu_bo(bo))
|
||||
@@ -1262,12 +1266,12 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, bool evict)
|
||||
amdgpu_bo_kunmap(abo);
|
||||
|
||||
if (abo->tbo.base.dma_buf && !abo->tbo.base.import_attach &&
|
||||
bo->resource->mem_type != TTM_PL_SYSTEM)
|
||||
old_mem && old_mem->mem_type != TTM_PL_SYSTEM)
|
||||
dma_buf_move_notify(abo->tbo.base.dma_buf);
|
||||
|
||||
/* remember the eviction */
|
||||
if (evict)
|
||||
atomic64_inc(&adev->num_evictions);
|
||||
/* move_notify is called before move happens */
|
||||
trace_amdgpu_bo_move(abo, new_mem ? new_mem->mem_type : -1,
|
||||
old_mem ? old_mem->mem_type : -1);
|
||||
}
|
||||
|
||||
void amdgpu_bo_get_memory(struct amdgpu_bo *bo,
|
||||
|
||||
@@ -328,7 +328,9 @@ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
|
||||
int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
|
||||
size_t buffer_size, uint32_t *metadata_size,
|
||||
uint64_t *flags);
|
||||
void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, bool evict);
|
||||
void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
|
||||
bool evict,
|
||||
struct ttm_resource *new_mem);
|
||||
void amdgpu_bo_release_notify(struct ttm_buffer_object *bo);
|
||||
vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
|
||||
void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence,
|
||||
|
||||
@@ -419,7 +419,7 @@ bool amdgpu_res_cpu_visible(struct amdgpu_device *adev,
|
||||
return false;
|
||||
|
||||
if (res->mem_type == TTM_PL_SYSTEM || res->mem_type == TTM_PL_TT ||
|
||||
res->mem_type == AMDGPU_PL_PREEMPT)
|
||||
res->mem_type == AMDGPU_PL_PREEMPT || res->mem_type == AMDGPU_PL_DOORBELL)
|
||||
return true;
|
||||
|
||||
if (res->mem_type != TTM_PL_VRAM)
|
||||
@@ -481,14 +481,16 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
|
||||
|
||||
if (!old_mem || (old_mem->mem_type == TTM_PL_SYSTEM &&
|
||||
bo->ttm == NULL)) {
|
||||
amdgpu_bo_move_notify(bo, evict, new_mem);
|
||||
ttm_bo_move_null(bo, new_mem);
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
if (old_mem->mem_type == TTM_PL_SYSTEM &&
|
||||
(new_mem->mem_type == TTM_PL_TT ||
|
||||
new_mem->mem_type == AMDGPU_PL_PREEMPT)) {
|
||||
amdgpu_bo_move_notify(bo, evict, new_mem);
|
||||
ttm_bo_move_null(bo, new_mem);
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
if ((old_mem->mem_type == TTM_PL_TT ||
|
||||
old_mem->mem_type == AMDGPU_PL_PREEMPT) &&
|
||||
@@ -498,9 +500,10 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
|
||||
return r;
|
||||
|
||||
amdgpu_ttm_backend_unbind(bo->bdev, bo->ttm);
|
||||
amdgpu_bo_move_notify(bo, evict, new_mem);
|
||||
ttm_resource_free(bo, &bo->resource);
|
||||
ttm_bo_assign_mem(bo, new_mem);
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (old_mem->mem_type == AMDGPU_PL_GDS ||
|
||||
@@ -512,8 +515,9 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
|
||||
new_mem->mem_type == AMDGPU_PL_OA ||
|
||||
new_mem->mem_type == AMDGPU_PL_DOORBELL) {
|
||||
/* Nothing to save here */
|
||||
amdgpu_bo_move_notify(bo, evict, new_mem);
|
||||
ttm_bo_move_null(bo, new_mem);
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bo->type == ttm_bo_type_device &&
|
||||
@@ -525,23 +529,24 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
|
||||
abo->flags &= ~AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
|
||||
}
|
||||
|
||||
if (adev->mman.buffer_funcs_enabled) {
|
||||
if (((old_mem->mem_type == TTM_PL_SYSTEM &&
|
||||
new_mem->mem_type == TTM_PL_VRAM) ||
|
||||
(old_mem->mem_type == TTM_PL_VRAM &&
|
||||
new_mem->mem_type == TTM_PL_SYSTEM))) {
|
||||
hop->fpfn = 0;
|
||||
hop->lpfn = 0;
|
||||
hop->mem_type = TTM_PL_TT;
|
||||
hop->flags = TTM_PL_FLAG_TEMPORARY;
|
||||
return -EMULTIHOP;
|
||||
}
|
||||
|
||||
r = amdgpu_move_blit(bo, evict, new_mem, old_mem);
|
||||
} else {
|
||||
r = -ENODEV;
|
||||
if (adev->mman.buffer_funcs_enabled &&
|
||||
((old_mem->mem_type == TTM_PL_SYSTEM &&
|
||||
new_mem->mem_type == TTM_PL_VRAM) ||
|
||||
(old_mem->mem_type == TTM_PL_VRAM &&
|
||||
new_mem->mem_type == TTM_PL_SYSTEM))) {
|
||||
hop->fpfn = 0;
|
||||
hop->lpfn = 0;
|
||||
hop->mem_type = TTM_PL_TT;
|
||||
hop->flags = TTM_PL_FLAG_TEMPORARY;
|
||||
return -EMULTIHOP;
|
||||
}
|
||||
|
||||
amdgpu_bo_move_notify(bo, evict, new_mem);
|
||||
if (adev->mman.buffer_funcs_enabled)
|
||||
r = amdgpu_move_blit(bo, evict, new_mem, old_mem);
|
||||
else
|
||||
r = -ENODEV;
|
||||
|
||||
if (r) {
|
||||
/* Check that all memory is CPU accessible */
|
||||
if (!amdgpu_res_copyable(adev, old_mem) ||
|
||||
@@ -555,11 +560,10 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
|
||||
return r;
|
||||
}
|
||||
|
||||
trace_amdgpu_bo_move(abo, new_mem->mem_type, old_mem->mem_type);
|
||||
out:
|
||||
/* update statistics */
|
||||
/* update statistics after the move */
|
||||
if (evict)
|
||||
atomic64_inc(&adev->num_evictions);
|
||||
atomic64_add(bo->base.size, &adev->num_bytes_moved);
|
||||
amdgpu_bo_move_notify(bo, evict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1559,7 +1563,7 @@ static int amdgpu_ttm_access_memory(struct ttm_buffer_object *bo,
|
||||
static void
|
||||
amdgpu_bo_delete_mem_notify(struct ttm_buffer_object *bo)
|
||||
{
|
||||
amdgpu_bo_move_notify(bo, false);
|
||||
amdgpu_bo_move_notify(bo, false, NULL);
|
||||
}
|
||||
|
||||
static struct ttm_device_funcs amdgpu_bo_driver = {
|
||||
|
||||
@@ -829,6 +829,14 @@ struct kfd_process *kfd_create_process(struct task_struct *thread)
|
||||
if (process) {
|
||||
pr_debug("Process already found\n");
|
||||
} else {
|
||||
/* If the process just called exec(3), it is possible that the
|
||||
* cleanup of the kfd_process (following the release of the mm
|
||||
* of the old process image) is still in the cleanup work queue.
|
||||
* Make sure to drain any job before trying to recreate any
|
||||
* resource for this process.
|
||||
*/
|
||||
flush_workqueue(kfd_process_wq);
|
||||
|
||||
process = create_process(thread);
|
||||
if (IS_ERR(process))
|
||||
goto out;
|
||||
|
||||
@@ -4537,15 +4537,18 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
|
||||
/* Determine whether to enable Replay support by default. */
|
||||
if (!(amdgpu_dc_debug_mask & DC_DISABLE_REPLAY)) {
|
||||
switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) {
|
||||
case IP_VERSION(3, 1, 4):
|
||||
case IP_VERSION(3, 1, 5):
|
||||
case IP_VERSION(3, 1, 6):
|
||||
case IP_VERSION(3, 2, 0):
|
||||
case IP_VERSION(3, 2, 1):
|
||||
case IP_VERSION(3, 5, 0):
|
||||
case IP_VERSION(3, 5, 1):
|
||||
replay_feature_enabled = true;
|
||||
break;
|
||||
/*
|
||||
* Disabled by default due to https://gitlab.freedesktop.org/drm/amd/-/issues/3344
|
||||
* case IP_VERSION(3, 1, 4):
|
||||
* case IP_VERSION(3, 1, 5):
|
||||
* case IP_VERSION(3, 1, 6):
|
||||
* case IP_VERSION(3, 2, 0):
|
||||
* case IP_VERSION(3, 2, 1):
|
||||
* case IP_VERSION(3, 5, 0):
|
||||
* case IP_VERSION(3, 5, 1):
|
||||
* replay_feature_enabled = true;
|
||||
* break;
|
||||
*/
|
||||
default:
|
||||
replay_feature_enabled = amdgpu_dc_feature_mask & DC_REPLAY_MASK;
|
||||
break;
|
||||
|
||||
@@ -1495,7 +1495,9 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf,
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx->stream &&
|
||||
pipe_ctx->stream->link == aconnector->dc_link)
|
||||
pipe_ctx->stream->link == aconnector->dc_link &&
|
||||
pipe_ctx->stream->sink &&
|
||||
pipe_ctx->stream->sink == aconnector->dc_sink)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1596,7 +1598,9 @@ static ssize_t dp_dsc_clock_en_write(struct file *f, const char __user *buf,
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx->stream &&
|
||||
pipe_ctx->stream->link == aconnector->dc_link)
|
||||
pipe_ctx->stream->link == aconnector->dc_link &&
|
||||
pipe_ctx->stream->sink &&
|
||||
pipe_ctx->stream->sink == aconnector->dc_sink)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1681,7 +1685,9 @@ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf,
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx->stream &&
|
||||
pipe_ctx->stream->link == aconnector->dc_link)
|
||||
pipe_ctx->stream->link == aconnector->dc_link &&
|
||||
pipe_ctx->stream->sink &&
|
||||
pipe_ctx->stream->sink == aconnector->dc_sink)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1780,7 +1786,9 @@ static ssize_t dp_dsc_slice_width_write(struct file *f, const char __user *buf,
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx->stream &&
|
||||
pipe_ctx->stream->link == aconnector->dc_link)
|
||||
pipe_ctx->stream->link == aconnector->dc_link &&
|
||||
pipe_ctx->stream->sink &&
|
||||
pipe_ctx->stream->sink == aconnector->dc_sink)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1865,7 +1873,9 @@ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf,
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx->stream &&
|
||||
pipe_ctx->stream->link == aconnector->dc_link)
|
||||
pipe_ctx->stream->link == aconnector->dc_link &&
|
||||
pipe_ctx->stream->sink &&
|
||||
pipe_ctx->stream->sink == aconnector->dc_sink)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1964,7 +1974,9 @@ static ssize_t dp_dsc_slice_height_write(struct file *f, const char __user *buf,
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx->stream &&
|
||||
pipe_ctx->stream->link == aconnector->dc_link)
|
||||
pipe_ctx->stream->link == aconnector->dc_link &&
|
||||
pipe_ctx->stream->sink &&
|
||||
pipe_ctx->stream->sink == aconnector->dc_sink)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2045,7 +2057,9 @@ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf,
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx->stream &&
|
||||
pipe_ctx->stream->link == aconnector->dc_link)
|
||||
pipe_ctx->stream->link == aconnector->dc_link &&
|
||||
pipe_ctx->stream->sink &&
|
||||
pipe_ctx->stream->sink == aconnector->dc_sink)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2141,7 +2155,9 @@ static ssize_t dp_dsc_bits_per_pixel_write(struct file *f, const char __user *bu
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx->stream &&
|
||||
pipe_ctx->stream->link == aconnector->dc_link)
|
||||
pipe_ctx->stream->link == aconnector->dc_link &&
|
||||
pipe_ctx->stream->sink &&
|
||||
pipe_ctx->stream->sink == aconnector->dc_sink)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2220,7 +2236,9 @@ static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf,
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx->stream &&
|
||||
pipe_ctx->stream->link == aconnector->dc_link)
|
||||
pipe_ctx->stream->link == aconnector->dc_link &&
|
||||
pipe_ctx->stream->sink &&
|
||||
pipe_ctx->stream->sink == aconnector->dc_sink)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2276,7 +2294,9 @@ static ssize_t dp_dsc_pic_height_read(struct file *f, char __user *buf,
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx->stream &&
|
||||
pipe_ctx->stream->link == aconnector->dc_link)
|
||||
pipe_ctx->stream->link == aconnector->dc_link &&
|
||||
pipe_ctx->stream->sink &&
|
||||
pipe_ctx->stream->sink == aconnector->dc_sink)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2347,7 +2367,9 @@ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf,
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx->stream &&
|
||||
pipe_ctx->stream->link == aconnector->dc_link)
|
||||
pipe_ctx->stream->link == aconnector->dc_link &&
|
||||
pipe_ctx->stream->sink &&
|
||||
pipe_ctx->stream->sink == aconnector->dc_sink)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2418,7 +2440,9 @@ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf,
|
||||
for (i = 0; i < MAX_PIPES; i++) {
|
||||
pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i];
|
||||
if (pipe_ctx->stream &&
|
||||
pipe_ctx->stream->link == aconnector->dc_link)
|
||||
pipe_ctx->stream->link == aconnector->dc_link &&
|
||||
pipe_ctx->stream->sink &&
|
||||
pipe_ctx->stream->sink == aconnector->dc_sink)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -2948,6 +2948,7 @@ static enum bp_result construct_integrated_info(
|
||||
result = get_integrated_info_v2_1(bp, info);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
result = get_integrated_info_v2_2(bp, info);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -145,6 +145,10 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base,
|
||||
*/
|
||||
clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
|
||||
if (safe_to_lower) {
|
||||
if (clk_mgr_base->clks.dtbclk_en && !new_clocks->dtbclk_en) {
|
||||
dcn315_smu_set_dtbclk(clk_mgr, false);
|
||||
clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en;
|
||||
}
|
||||
/* check that we're not already in lower */
|
||||
if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
|
||||
display_count = dcn315_get_active_display_cnt_wa(dc, context);
|
||||
@@ -160,6 +164,10 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) {
|
||||
dcn315_smu_set_dtbclk(clk_mgr, true);
|
||||
clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en;
|
||||
}
|
||||
/* check that we're not already in D0 */
|
||||
if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) {
|
||||
union display_idle_optimization_u idle_info = { 0 };
|
||||
|
||||
@@ -712,8 +712,12 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
|
||||
* since we calculate mode support based on softmax being the max UCLK
|
||||
* frequency.
|
||||
*/
|
||||
dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
|
||||
dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
|
||||
if (dc->debug.disable_dc_mode_overwrite) {
|
||||
dcn30_smu_set_hard_max_by_freq(clk_mgr, PPCLK_UCLK, dc->clk_mgr->bw_params->max_memclk_mhz);
|
||||
dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, dc->clk_mgr->bw_params->max_memclk_mhz);
|
||||
} else
|
||||
dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
|
||||
dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
|
||||
} else {
|
||||
dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, dc->clk_mgr->bw_params->max_memclk_mhz);
|
||||
}
|
||||
@@ -746,8 +750,13 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base,
|
||||
/* set UCLK to requested value if P-State switching is supported, or to re-enable P-State switching */
|
||||
if (clk_mgr_base->clks.p_state_change_support &&
|
||||
(update_uclk || !clk_mgr_base->clks.prev_p_state_change_support) &&
|
||||
!dc->work_arounds.clock_update_disable_mask.uclk)
|
||||
!dc->work_arounds.clock_update_disable_mask.uclk) {
|
||||
if (dc->clk_mgr->dc_mode_softmax_enabled && dc->debug.disable_dc_mode_overwrite)
|
||||
dcn30_smu_set_hard_max_by_freq(clk_mgr, PPCLK_UCLK,
|
||||
max((int)dc->clk_mgr->bw_params->dc_mode_softmax_memclk, khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz)));
|
||||
|
||||
dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz));
|
||||
}
|
||||
|
||||
if (clk_mgr_base->clks.num_ways != new_clocks->num_ways &&
|
||||
clk_mgr_base->clks.num_ways > new_clocks->num_ways) {
|
||||
|
||||
@@ -1801,6 +1801,9 @@ bool dc_validate_boot_timing(const struct dc *dc,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED)
|
||||
return false;
|
||||
|
||||
if (dc->link_srv->edp_is_ilr_optimization_required(link, crtc_timing)) {
|
||||
DC_LOG_EVENT_LINK_TRAINING("Seamless boot disabled to optimize eDP link rate\n");
|
||||
return false;
|
||||
|
||||
@@ -395,6 +395,12 @@ void dcn31_hpo_dp_link_enc_set_throttled_vcp_size(
|
||||
x),
|
||||
25));
|
||||
|
||||
// If y rounds up to integer, carry it over to x.
|
||||
if (y >> 25) {
|
||||
x += 1;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
switch (stream_encoder_inst) {
|
||||
case 0:
|
||||
REG_SET_2(DP_DPHY_SYM32_VC_RATE_CNTL0, 0,
|
||||
|
||||
@@ -291,6 +291,7 @@ static struct _vcs_dpi_soc_bounding_box_st dcn3_15_soc = {
|
||||
.do_urgent_latency_adjustment = false,
|
||||
.urgent_latency_adjustment_fabric_clock_component_us = 0,
|
||||
.urgent_latency_adjustment_fabric_clock_reference_mhz = 0,
|
||||
.dispclk_dppclk_vco_speed_mhz = 2400.0,
|
||||
.num_chans = 4,
|
||||
.dummy_pstate_latency_us = 10.0
|
||||
};
|
||||
@@ -438,6 +439,7 @@ static struct _vcs_dpi_soc_bounding_box_st dcn3_16_soc = {
|
||||
.do_urgent_latency_adjustment = false,
|
||||
.urgent_latency_adjustment_fabric_clock_component_us = 0,
|
||||
.urgent_latency_adjustment_fabric_clock_reference_mhz = 0,
|
||||
.dispclk_dppclk_vco_speed_mhz = 2500.0,
|
||||
};
|
||||
|
||||
void dcn31_zero_pipe_dcc_fraction(display_e2e_pipe_params_st *pipes,
|
||||
|
||||
@@ -270,7 +270,7 @@ static void set_usb4_req_bw_req(struct dc_link *link, int req_bw)
|
||||
|
||||
/* Error check whether requested and allocated are equal */
|
||||
req_bw = requested_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity);
|
||||
if (req_bw == link->dpia_bw_alloc_config.allocated_bw) {
|
||||
if (req_bw && (req_bw == link->dpia_bw_alloc_config.allocated_bw)) {
|
||||
DC_LOG_ERROR("%s: Request bw equals to allocated bw for link(%d)\n",
|
||||
__func__, link->link_index);
|
||||
}
|
||||
@@ -341,6 +341,14 @@ bool link_dp_dpia_set_dptx_usb4_bw_alloc_support(struct dc_link *link)
|
||||
ret = true;
|
||||
init_usb4_bw_struct(link);
|
||||
link->dpia_bw_alloc_config.bw_alloc_enabled = true;
|
||||
|
||||
/*
|
||||
* During DP tunnel creation, CM preallocates BW and reduces estimated BW of other
|
||||
* DPIA. CM release preallocation only when allocation is complete. Do zero alloc
|
||||
* to make the CM to release preallocation and update estimated BW correctly for
|
||||
* all DPIAs per host router
|
||||
*/
|
||||
link_dp_dpia_allocate_usb4_bandwidth_for_stream(link, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2449,6 +2449,7 @@ static bool dcn20_resource_construct(
|
||||
dc->caps.post_blend_color_processing = true;
|
||||
dc->caps.force_dp_tps4_for_cp2520 = true;
|
||||
dc->caps.extended_aux_timeout_support = true;
|
||||
dc->caps.dmcub_support = true;
|
||||
|
||||
/* Color pipeline capabilities */
|
||||
dc->caps.color.dpp.dcn_arch = 1;
|
||||
|
||||
@@ -7,13 +7,14 @@
|
||||
#include "pvr_rogue_mips.h"
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* Forward declaration from pvr_gem.h. */
|
||||
struct pvr_gem_object;
|
||||
|
||||
#define PVR_MIPS_PT_PAGE_COUNT ((ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES * ROGUE_MIPSFW_PAGE_SIZE_4K) \
|
||||
>> PAGE_SHIFT)
|
||||
#define PVR_MIPS_PT_PAGE_COUNT DIV_ROUND_UP(ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES * ROGUE_MIPSFW_PAGE_SIZE_4K, PAGE_SIZE)
|
||||
|
||||
/**
|
||||
* struct pvr_fw_mips_data - MIPS-specific data
|
||||
*/
|
||||
|
||||
@@ -15,7 +15,9 @@ struct nvkm_gsp_mem {
|
||||
};
|
||||
|
||||
struct nvkm_gsp_radix3 {
|
||||
struct nvkm_gsp_mem mem[3];
|
||||
struct nvkm_gsp_mem lvl0;
|
||||
struct nvkm_gsp_mem lvl1;
|
||||
struct sg_table lvl2;
|
||||
};
|
||||
|
||||
int nvkm_gsp_sg(struct nvkm_device *, u64 size, struct sg_table *);
|
||||
|
||||
@@ -205,7 +205,9 @@ nvkm_firmware_dtor(struct nvkm_firmware *fw)
|
||||
break;
|
||||
case NVKM_FIRMWARE_IMG_DMA:
|
||||
nvkm_memory_unref(&memory);
|
||||
dma_free_coherent(fw->device->dev, sg_dma_len(&fw->mem.sgl), fw->img, fw->phys);
|
||||
dma_unmap_single(fw->device->dev, fw->phys, sg_dma_len(&fw->mem.sgl),
|
||||
DMA_TO_DEVICE);
|
||||
kfree(fw->img);
|
||||
break;
|
||||
case NVKM_FIRMWARE_IMG_SGT:
|
||||
nvkm_memory_unref(&memory);
|
||||
@@ -235,14 +237,17 @@ nvkm_firmware_ctor(const struct nvkm_firmware_func *func, const char *name,
|
||||
fw->img = kmemdup(src, fw->len, GFP_KERNEL);
|
||||
break;
|
||||
case NVKM_FIRMWARE_IMG_DMA: {
|
||||
dma_addr_t addr;
|
||||
|
||||
len = ALIGN(fw->len, PAGE_SIZE);
|
||||
|
||||
fw->img = dma_alloc_coherent(fw->device->dev, len, &addr, GFP_KERNEL);
|
||||
if (fw->img) {
|
||||
memcpy(fw->img, src, fw->len);
|
||||
fw->phys = addr;
|
||||
fw->img = kmalloc(len, GFP_KERNEL);
|
||||
if (!fw->img)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(fw->img, src, fw->len);
|
||||
fw->phys = dma_map_single(fw->device->dev, fw->img, len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(fw->device->dev, fw->phys)) {
|
||||
kfree(fw->img);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
sg_init_one(&fw->mem.sgl, fw->img, len);
|
||||
|
||||
@@ -1624,7 +1624,7 @@ r535_gsp_wpr_meta_init(struct nvkm_gsp *gsp)
|
||||
meta->magic = GSP_FW_WPR_META_MAGIC;
|
||||
meta->revision = GSP_FW_WPR_META_REVISION;
|
||||
|
||||
meta->sysmemAddrOfRadix3Elf = gsp->radix3.mem[0].addr;
|
||||
meta->sysmemAddrOfRadix3Elf = gsp->radix3.lvl0.addr;
|
||||
meta->sizeOfRadix3Elf = gsp->fb.wpr2.elf.size;
|
||||
|
||||
meta->sysmemAddrOfBootloader = gsp->boot.fw.addr;
|
||||
@@ -1919,8 +1919,9 @@ nvkm_gsp_sg(struct nvkm_device *device, u64 size, struct sg_table *sgt)
|
||||
static void
|
||||
nvkm_gsp_radix3_dtor(struct nvkm_gsp *gsp, struct nvkm_gsp_radix3 *rx3)
|
||||
{
|
||||
for (int i = ARRAY_SIZE(rx3->mem) - 1; i >= 0; i--)
|
||||
nvkm_gsp_mem_dtor(gsp, &rx3->mem[i]);
|
||||
nvkm_gsp_sg_free(gsp->subdev.device, &rx3->lvl2);
|
||||
nvkm_gsp_mem_dtor(gsp, &rx3->lvl1);
|
||||
nvkm_gsp_mem_dtor(gsp, &rx3->lvl0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1960,36 +1961,60 @@ static int
|
||||
nvkm_gsp_radix3_sg(struct nvkm_gsp *gsp, struct sg_table *sgt, u64 size,
|
||||
struct nvkm_gsp_radix3 *rx3)
|
||||
{
|
||||
u64 addr;
|
||||
struct sg_dma_page_iter sg_dma_iter;
|
||||
struct scatterlist *sg;
|
||||
size_t bufsize;
|
||||
u64 *pte;
|
||||
int ret, i, page_idx = 0;
|
||||
|
||||
for (int i = ARRAY_SIZE(rx3->mem) - 1; i >= 0; i--) {
|
||||
u64 *ptes;
|
||||
size_t bufsize;
|
||||
int ret, idx;
|
||||
ret = nvkm_gsp_mem_ctor(gsp, GSP_PAGE_SIZE, &rx3->lvl0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bufsize = ALIGN((size / GSP_PAGE_SIZE) * sizeof(u64), GSP_PAGE_SIZE);
|
||||
ret = nvkm_gsp_mem_ctor(gsp, bufsize, &rx3->mem[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nvkm_gsp_mem_ctor(gsp, GSP_PAGE_SIZE, &rx3->lvl1);
|
||||
if (ret)
|
||||
goto lvl1_fail;
|
||||
|
||||
ptes = rx3->mem[i].data;
|
||||
if (i == 2) {
|
||||
struct scatterlist *sgl;
|
||||
// Allocate level 2
|
||||
bufsize = ALIGN((size / GSP_PAGE_SIZE) * sizeof(u64), GSP_PAGE_SIZE);
|
||||
ret = nvkm_gsp_sg(gsp->subdev.device, bufsize, &rx3->lvl2);
|
||||
if (ret)
|
||||
goto lvl2_fail;
|
||||
|
||||
for_each_sgtable_dma_sg(sgt, sgl, idx) {
|
||||
for (int j = 0; j < sg_dma_len(sgl) / GSP_PAGE_SIZE; j++)
|
||||
*ptes++ = sg_dma_address(sgl) + (GSP_PAGE_SIZE * j);
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < size / GSP_PAGE_SIZE; j++)
|
||||
*ptes++ = addr + GSP_PAGE_SIZE * j;
|
||||
// Write the bus address of level 1 to level 0
|
||||
pte = rx3->lvl0.data;
|
||||
*pte = rx3->lvl1.addr;
|
||||
|
||||
// Write the bus address of each page in level 2 to level 1
|
||||
pte = rx3->lvl1.data;
|
||||
for_each_sgtable_dma_page(&rx3->lvl2, &sg_dma_iter, 0)
|
||||
*pte++ = sg_page_iter_dma_address(&sg_dma_iter);
|
||||
|
||||
// Finally, write the bus address of each page in sgt to level 2
|
||||
for_each_sgtable_sg(&rx3->lvl2, sg, i) {
|
||||
void *sgl_end;
|
||||
|
||||
pte = sg_virt(sg);
|
||||
sgl_end = (void *)pte + sg->length;
|
||||
|
||||
for_each_sgtable_dma_page(sgt, &sg_dma_iter, page_idx) {
|
||||
*pte++ = sg_page_iter_dma_address(&sg_dma_iter);
|
||||
page_idx++;
|
||||
|
||||
// Go to the next scatterlist for level 2 if we've reached the end
|
||||
if ((void *)pte >= sgl_end)
|
||||
break;
|
||||
}
|
||||
|
||||
size = rx3->mem[i].size;
|
||||
addr = rx3->mem[i].addr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (ret) {
|
||||
lvl2_fail:
|
||||
nvkm_gsp_mem_dtor(gsp, &rx3->lvl1);
|
||||
lvl1_fail:
|
||||
nvkm_gsp_mem_dtor(gsp, &rx3->lvl0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -2021,7 +2046,7 @@ r535_gsp_fini(struct nvkm_gsp *gsp, bool suspend)
|
||||
sr = gsp->sr.meta.data;
|
||||
sr->magic = GSP_FW_SR_META_MAGIC;
|
||||
sr->revision = GSP_FW_SR_META_REVISION;
|
||||
sr->sysmemAddrOfSuspendResumeData = gsp->sr.radix3.mem[0].addr;
|
||||
sr->sysmemAddrOfSuspendResumeData = gsp->sr.radix3.lvl0.addr;
|
||||
sr->sizeOfSuspendResumeData = len;
|
||||
|
||||
mbox0 = lower_32_bits(gsp->sr.meta.addr);
|
||||
|
||||
@@ -177,7 +177,7 @@ config DRM_PANEL_ILITEK_IL9322
|
||||
|
||||
config DRM_PANEL_ILITEK_ILI9341
|
||||
tristate "Ilitek ILI9341 240x320 QVGA panels"
|
||||
depends on OF && SPI
|
||||
depends on SPI
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_GEM_DMA_HELPER
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
|
||||
@@ -22,8 +22,9 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
@@ -421,7 +422,7 @@ static int ili9341_dpi_prepare(struct drm_panel *panel)
|
||||
|
||||
ili9341_dpi_init(ili);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ili9341_dpi_enable(struct drm_panel *panel)
|
||||
@@ -691,7 +692,7 @@ static int ili9341_dpi_probe(struct spi_device *spi, struct gpio_desc *dc,
|
||||
* Every new incarnation of this display must have a unique
|
||||
* data entry for the system in this driver.
|
||||
*/
|
||||
ili->conf = of_device_get_match_data(dev);
|
||||
ili->conf = device_get_match_data(dev);
|
||||
if (!ili->conf) {
|
||||
dev_err(dev, "missing device configuration\n");
|
||||
return -ENODEV;
|
||||
@@ -714,18 +715,18 @@ static int ili9341_probe(struct spi_device *spi)
|
||||
|
||||
reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(reset))
|
||||
dev_err(dev, "Failed to get gpio 'reset'\n");
|
||||
return dev_err_probe(dev, PTR_ERR(reset), "Failed to get gpio 'reset'\n");
|
||||
|
||||
dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(dc))
|
||||
dev_err(dev, "Failed to get gpio 'dc'\n");
|
||||
return dev_err_probe(dev, PTR_ERR(dc), "Failed to get gpio 'dc'\n");
|
||||
|
||||
if (!strcmp(id->name, "sf-tc240t-9370-t"))
|
||||
return ili9341_dpi_probe(spi, dc, reset);
|
||||
else if (!strcmp(id->name, "yx240qv29"))
|
||||
return ili9341_dbi_probe(spi, dc, reset);
|
||||
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void ili9341_remove(struct spi_device *spi)
|
||||
|
||||
@@ -92,7 +92,7 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc)
|
||||
*/
|
||||
if (bdev->pool.use_dma_alloc && cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) {
|
||||
page_flags |= TTM_TT_FLAG_DECRYPTED;
|
||||
drm_info(ddev, "TT memory decryption enabled.");
|
||||
drm_info_once(ddev, "TT memory decryption enabled.");
|
||||
}
|
||||
|
||||
bo->ttm = bdev->funcs->ttm_tt_create(bo, page_flags);
|
||||
|
||||
@@ -204,6 +204,7 @@ int vmw_bo_pin_in_start_of_vram(struct vmw_private *dev_priv,
|
||||
VMW_BO_DOMAIN_VRAM,
|
||||
VMW_BO_DOMAIN_VRAM);
|
||||
buf->places[0].lpfn = PFN_UP(bo->resource->size);
|
||||
buf->busy_places[0].lpfn = PFN_UP(bo->resource->size);
|
||||
ret = ttm_bo_validate(bo, &buf->placement, &ctx);
|
||||
|
||||
/* For some reason we didn't end up at the start of vram */
|
||||
|
||||
@@ -991,7 +991,7 @@ static int vmw_event_fence_action_create(struct drm_file *file_priv,
|
||||
}
|
||||
|
||||
event->event.base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
|
||||
event->event.base.length = sizeof(*event);
|
||||
event->event.base.length = sizeof(event->event);
|
||||
event->event.user_data = user_data;
|
||||
|
||||
ret = drm_event_reserve_init(dev, file_priv, &event->base, &event->event.base);
|
||||
|
||||
@@ -84,7 +84,8 @@ static inline struct drm_i915_private *kdev_to_i915(struct device *kdev)
|
||||
#define IS_ROCKETLAKE(dev_priv) IS_PLATFORM(dev_priv, XE_ROCKETLAKE)
|
||||
#define IS_DG1(dev_priv) IS_PLATFORM(dev_priv, XE_DG1)
|
||||
#define IS_ALDERLAKE_S(dev_priv) IS_PLATFORM(dev_priv, XE_ALDERLAKE_S)
|
||||
#define IS_ALDERLAKE_P(dev_priv) IS_PLATFORM(dev_priv, XE_ALDERLAKE_P)
|
||||
#define IS_ALDERLAKE_P(dev_priv) (IS_PLATFORM(dev_priv, XE_ALDERLAKE_P) || \
|
||||
IS_PLATFORM(dev_priv, XE_ALDERLAKE_N))
|
||||
#define IS_XEHPSDV(dev_priv) (dev_priv && 0)
|
||||
#define IS_DG2(dev_priv) IS_PLATFORM(dev_priv, XE_DG2)
|
||||
#define IS_PONTEVECCHIO(dev_priv) IS_PLATFORM(dev_priv, XE_PVC)
|
||||
|
||||
@@ -1606,6 +1606,9 @@ static void vm_destroy_work_func(struct work_struct *w)
|
||||
/* xe_vm_close_and_put was not called? */
|
||||
xe_assert(xe, !vm->size);
|
||||
|
||||
if (xe_vm_in_preempt_fence_mode(vm))
|
||||
flush_work(&vm->preempt.rebind_work);
|
||||
|
||||
mutex_destroy(&vm->snap_mutex);
|
||||
|
||||
if (!(vm->flags & XE_VM_FLAG_MIGRATION))
|
||||
|
||||
@@ -628,27 +628,6 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nvme_change_ctrl_state);
|
||||
|
||||
/*
|
||||
* Returns true for sink states that can't ever transition back to live.
|
||||
*/
|
||||
static bool nvme_state_terminal(struct nvme_ctrl *ctrl)
|
||||
{
|
||||
switch (nvme_ctrl_state(ctrl)) {
|
||||
case NVME_CTRL_NEW:
|
||||
case NVME_CTRL_LIVE:
|
||||
case NVME_CTRL_RESETTING:
|
||||
case NVME_CTRL_CONNECTING:
|
||||
return false;
|
||||
case NVME_CTRL_DELETING:
|
||||
case NVME_CTRL_DELETING_NOIO:
|
||||
case NVME_CTRL_DEAD:
|
||||
return true;
|
||||
default:
|
||||
WARN_ONCE(1, "Unhandled ctrl state:%d", ctrl->state);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Waits for the controller state to be resetting, or returns false if it is
|
||||
* not possible to ever transition to that state.
|
||||
@@ -3681,7 +3660,7 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info)
|
||||
"Found shared namespace %d, but multipathing not supported.\n",
|
||||
info->nsid);
|
||||
dev_warn_once(ctrl->device,
|
||||
"Support for shared namespaces without CONFIG_NVME_MULTIPATH is deprecated and will be removed in Linux 6.0\n.");
|
||||
"Support for shared namespaces without CONFIG_NVME_MULTIPATH is deprecated and will be removed in Linux 6.0.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -247,7 +247,8 @@ static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node)
|
||||
if (nvme_path_is_disabled(ns))
|
||||
continue;
|
||||
|
||||
if (READ_ONCE(head->subsys->iopolicy) == NVME_IOPOLICY_NUMA)
|
||||
if (ns->ctrl->numa_node != NUMA_NO_NODE &&
|
||||
READ_ONCE(head->subsys->iopolicy) == NVME_IOPOLICY_NUMA)
|
||||
distance = node_distance(node, ns->ctrl->numa_node);
|
||||
else
|
||||
distance = LOCAL_DISTANCE;
|
||||
|
||||
@@ -741,6 +741,27 @@ static inline bool nvme_is_aen_req(u16 qid, __u16 command_id)
|
||||
nvme_tag_from_cid(command_id) >= NVME_AQ_BLK_MQ_DEPTH;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true for sink states that can't ever transition back to live.
|
||||
*/
|
||||
static inline bool nvme_state_terminal(struct nvme_ctrl *ctrl)
|
||||
{
|
||||
switch (nvme_ctrl_state(ctrl)) {
|
||||
case NVME_CTRL_NEW:
|
||||
case NVME_CTRL_LIVE:
|
||||
case NVME_CTRL_RESETTING:
|
||||
case NVME_CTRL_CONNECTING:
|
||||
return false;
|
||||
case NVME_CTRL_DELETING:
|
||||
case NVME_CTRL_DELETING_NOIO:
|
||||
case NVME_CTRL_DEAD:
|
||||
return true;
|
||||
default:
|
||||
WARN_ONCE(1, "Unhandled ctrl state:%d", ctrl->state);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void nvme_complete_rq(struct request *req);
|
||||
void nvme_complete_batch_req(struct request *req);
|
||||
|
||||
|
||||
@@ -1286,6 +1286,9 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req)
|
||||
u32 csts = readl(dev->bar + NVME_REG_CSTS);
|
||||
u8 opcode;
|
||||
|
||||
if (nvme_state_terminal(&dev->ctrl))
|
||||
goto disable;
|
||||
|
||||
/* If PCI error recovery process is happening, we cannot reset or
|
||||
* the recovery mechanism will surely fail.
|
||||
*/
|
||||
@@ -1390,8 +1393,11 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req)
|
||||
return BLK_EH_RESET_TIMER;
|
||||
|
||||
disable:
|
||||
if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING))
|
||||
if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING)) {
|
||||
if (nvme_state_terminal(&dev->ctrl))
|
||||
nvme_dev_disable(dev, true);
|
||||
return BLK_EH_DONE;
|
||||
}
|
||||
|
||||
nvme_dev_disable(dev, false);
|
||||
if (nvme_try_sched_reset(&dev->ctrl))
|
||||
|
||||
@@ -360,12 +360,18 @@ static inline void nvme_tcp_send_all(struct nvme_tcp_queue *queue)
|
||||
} while (ret > 0);
|
||||
}
|
||||
|
||||
static inline bool nvme_tcp_queue_more(struct nvme_tcp_queue *queue)
|
||||
static inline bool nvme_tcp_queue_has_pending(struct nvme_tcp_queue *queue)
|
||||
{
|
||||
return !list_empty(&queue->send_list) ||
|
||||
!llist_empty(&queue->req_list);
|
||||
}
|
||||
|
||||
static inline bool nvme_tcp_queue_more(struct nvme_tcp_queue *queue)
|
||||
{
|
||||
return !nvme_tcp_tls(&queue->ctrl->ctrl) &&
|
||||
nvme_tcp_queue_has_pending(queue);
|
||||
}
|
||||
|
||||
static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
|
||||
bool sync, bool last)
|
||||
{
|
||||
@@ -386,7 +392,7 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
|
||||
mutex_unlock(&queue->send_mutex);
|
||||
}
|
||||
|
||||
if (last && nvme_tcp_queue_more(queue))
|
||||
if (last && nvme_tcp_queue_has_pending(queue))
|
||||
queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);
|
||||
}
|
||||
|
||||
|
||||
@@ -285,9 +285,9 @@ int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response,
|
||||
}
|
||||
|
||||
if (shash_len != crypto_shash_digestsize(shash_tfm)) {
|
||||
pr_debug("%s: hash len mismatch (len %d digest %d)\n",
|
||||
__func__, shash_len,
|
||||
crypto_shash_digestsize(shash_tfm));
|
||||
pr_err("%s: hash len mismatch (len %d digest %d)\n",
|
||||
__func__, shash_len,
|
||||
crypto_shash_digestsize(shash_tfm));
|
||||
ret = -EINVAL;
|
||||
goto out_free_tfm;
|
||||
}
|
||||
@@ -370,7 +370,7 @@ out_free_response:
|
||||
nvme_auth_free_key(transformed_key);
|
||||
out_free_tfm:
|
||||
crypto_free_shash(shash_tfm);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response,
|
||||
|
||||
@@ -754,6 +754,19 @@ static struct configfs_attribute *nvmet_ns_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
bool nvmet_subsys_nsid_exists(struct nvmet_subsys *subsys, u32 nsid)
|
||||
{
|
||||
struct config_item *ns_item;
|
||||
char name[4] = {};
|
||||
|
||||
if (sprintf(name, "%u", nsid) <= 0)
|
||||
return false;
|
||||
mutex_lock(&subsys->namespaces_group.cg_subsys->su_mutex);
|
||||
ns_item = config_group_find_item(&subsys->namespaces_group, name);
|
||||
mutex_unlock(&subsys->namespaces_group.cg_subsys->su_mutex);
|
||||
return ns_item != NULL;
|
||||
}
|
||||
|
||||
static void nvmet_ns_release(struct config_item *item)
|
||||
{
|
||||
struct nvmet_ns *ns = to_nvmet_ns(item);
|
||||
|
||||
@@ -437,10 +437,13 @@ void nvmet_stop_keep_alive_timer(struct nvmet_ctrl *ctrl)
|
||||
u16 nvmet_req_find_ns(struct nvmet_req *req)
|
||||
{
|
||||
u32 nsid = le32_to_cpu(req->cmd->common.nsid);
|
||||
struct nvmet_subsys *subsys = nvmet_req_subsys(req);
|
||||
|
||||
req->ns = xa_load(&nvmet_req_subsys(req)->namespaces, nsid);
|
||||
req->ns = xa_load(&subsys->namespaces, nsid);
|
||||
if (unlikely(!req->ns)) {
|
||||
req->error_loc = offsetof(struct nvme_common_command, nsid);
|
||||
if (nvmet_subsys_nsid_exists(subsys, nsid))
|
||||
return NVME_SC_INTERNAL_PATH_ERROR;
|
||||
return NVME_SC_INVALID_NS | NVME_SC_DNR;
|
||||
}
|
||||
|
||||
|
||||
@@ -543,6 +543,7 @@ void nvmet_subsys_disc_changed(struct nvmet_subsys *subsys,
|
||||
struct nvmet_host *host);
|
||||
void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type,
|
||||
u8 event_info, u8 log_page);
|
||||
bool nvmet_subsys_nsid_exists(struct nvmet_subsys *subsys, u32 nsid);
|
||||
|
||||
#define NVMET_MIN_QUEUE_SIZE 16
|
||||
#define NVMET_MAX_QUEUE_SIZE 1024
|
||||
|
||||
@@ -348,6 +348,7 @@ static int nvmet_tcp_check_ddgst(struct nvmet_tcp_queue *queue, void *pdu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If cmd buffers are NULL, no operation is performed */
|
||||
static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd)
|
||||
{
|
||||
kfree(cmd->iov);
|
||||
@@ -1581,13 +1582,9 @@ static void nvmet_tcp_free_cmd_data_in_buffers(struct nvmet_tcp_queue *queue)
|
||||
struct nvmet_tcp_cmd *cmd = queue->cmds;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < queue->nr_cmds; i++, cmd++) {
|
||||
if (nvmet_tcp_need_data_in(cmd))
|
||||
nvmet_tcp_free_cmd_buffers(cmd);
|
||||
}
|
||||
|
||||
if (!queue->nr_cmds && nvmet_tcp_need_data_in(&queue->connect))
|
||||
nvmet_tcp_free_cmd_buffers(&queue->connect);
|
||||
for (i = 0; i < queue->nr_cmds; i++, cmd++)
|
||||
nvmet_tcp_free_cmd_buffers(cmd);
|
||||
nvmet_tcp_free_cmd_buffers(&queue->connect);
|
||||
}
|
||||
|
||||
static void nvmet_tcp_release_queue_work(struct work_struct *w)
|
||||
|
||||
+97
-51
@@ -37,6 +37,7 @@ static DEFINE_MUTEX(eventfs_mutex);
|
||||
|
||||
struct eventfs_root_inode {
|
||||
struct eventfs_inode ei;
|
||||
struct inode *parent_inode;
|
||||
struct dentry *events_dir;
|
||||
};
|
||||
|
||||
@@ -68,11 +69,25 @@ enum {
|
||||
EVENTFS_SAVE_MODE = BIT(16),
|
||||
EVENTFS_SAVE_UID = BIT(17),
|
||||
EVENTFS_SAVE_GID = BIT(18),
|
||||
EVENTFS_TOPLEVEL = BIT(19),
|
||||
};
|
||||
|
||||
#define EVENTFS_MODE_MASK (EVENTFS_SAVE_MODE - 1)
|
||||
|
||||
static void free_ei_rcu(struct rcu_head *rcu)
|
||||
{
|
||||
struct eventfs_inode *ei = container_of(rcu, struct eventfs_inode, rcu);
|
||||
struct eventfs_root_inode *rei;
|
||||
|
||||
kfree(ei->entry_attrs);
|
||||
kfree_const(ei->name);
|
||||
if (ei->is_events) {
|
||||
rei = get_root_inode(ei);
|
||||
kfree(rei);
|
||||
} else {
|
||||
kfree(ei);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* eventfs_inode reference count management.
|
||||
*
|
||||
@@ -84,18 +99,17 @@ enum {
|
||||
static void release_ei(struct kref *ref)
|
||||
{
|
||||
struct eventfs_inode *ei = container_of(ref, struct eventfs_inode, kref);
|
||||
struct eventfs_root_inode *rei;
|
||||
const struct eventfs_entry *entry;
|
||||
|
||||
WARN_ON_ONCE(!ei->is_freed);
|
||||
|
||||
kfree(ei->entry_attrs);
|
||||
kfree_const(ei->name);
|
||||
if (ei->is_events) {
|
||||
rei = get_root_inode(ei);
|
||||
kfree_rcu(rei, ei.rcu);
|
||||
} else {
|
||||
kfree_rcu(ei, rcu);
|
||||
for (int i = 0; i < ei->nr_entries; i++) {
|
||||
entry = &ei->entries[i];
|
||||
if (entry->release)
|
||||
entry->release(entry->name, ei->data);
|
||||
}
|
||||
|
||||
call_rcu(&ei->rcu, free_ei_rcu);
|
||||
}
|
||||
|
||||
static inline void put_ei(struct eventfs_inode *ei)
|
||||
@@ -112,6 +126,18 @@ static inline void free_ei(struct eventfs_inode *ei)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when creation of an ei fails, do not call release() functions.
|
||||
*/
|
||||
static inline void cleanup_ei(struct eventfs_inode *ei)
|
||||
{
|
||||
if (ei) {
|
||||
/* Set nr_entries to 0 to prevent release() function being called */
|
||||
ei->nr_entries = 0;
|
||||
free_ei(ei);
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct eventfs_inode *get_ei(struct eventfs_inode *ei)
|
||||
{
|
||||
if (ei)
|
||||
@@ -181,21 +207,7 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
* determined by the parent directory.
|
||||
*/
|
||||
if (dentry->d_inode->i_mode & S_IFDIR) {
|
||||
/*
|
||||
* The events directory dentry is never freed, unless its
|
||||
* part of an instance that is deleted. It's attr is the
|
||||
* default for its child files and directories.
|
||||
* Do not update it. It's not used for its own mode or ownership.
|
||||
*/
|
||||
if (ei->is_events) {
|
||||
/* But it still needs to know if it was modified */
|
||||
if (iattr->ia_valid & ATTR_UID)
|
||||
ei->attr.mode |= EVENTFS_SAVE_UID;
|
||||
if (iattr->ia_valid & ATTR_GID)
|
||||
ei->attr.mode |= EVENTFS_SAVE_GID;
|
||||
} else {
|
||||
update_attr(&ei->attr, iattr);
|
||||
}
|
||||
update_attr(&ei->attr, iattr);
|
||||
|
||||
} else {
|
||||
name = dentry->d_name.name;
|
||||
@@ -213,18 +225,25 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void update_top_events_attr(struct eventfs_inode *ei, struct super_block *sb)
|
||||
static void update_events_attr(struct eventfs_inode *ei, struct super_block *sb)
|
||||
{
|
||||
struct inode *root;
|
||||
struct eventfs_root_inode *rei;
|
||||
struct inode *parent;
|
||||
|
||||
/* Only update if the "events" was on the top level */
|
||||
if (!ei || !(ei->attr.mode & EVENTFS_TOPLEVEL))
|
||||
return;
|
||||
rei = get_root_inode(ei);
|
||||
|
||||
/* Get the tracefs root inode. */
|
||||
root = d_inode(sb->s_root);
|
||||
ei->attr.uid = root->i_uid;
|
||||
ei->attr.gid = root->i_gid;
|
||||
/* Use the parent inode permissions unless root set its permissions */
|
||||
parent = rei->parent_inode;
|
||||
|
||||
if (rei->ei.attr.mode & EVENTFS_SAVE_UID)
|
||||
ei->attr.uid = rei->ei.attr.uid;
|
||||
else
|
||||
ei->attr.uid = parent->i_uid;
|
||||
|
||||
if (rei->ei.attr.mode & EVENTFS_SAVE_GID)
|
||||
ei->attr.gid = rei->ei.attr.gid;
|
||||
else
|
||||
ei->attr.gid = parent->i_gid;
|
||||
}
|
||||
|
||||
static void set_top_events_ownership(struct inode *inode)
|
||||
@@ -233,10 +252,10 @@ static void set_top_events_ownership(struct inode *inode)
|
||||
struct eventfs_inode *ei = ti->private;
|
||||
|
||||
/* The top events directory doesn't get automatically updated */
|
||||
if (!ei || !ei->is_events || !(ei->attr.mode & EVENTFS_TOPLEVEL))
|
||||
if (!ei || !ei->is_events)
|
||||
return;
|
||||
|
||||
update_top_events_attr(ei, inode->i_sb);
|
||||
update_events_attr(ei, inode->i_sb);
|
||||
|
||||
if (!(ei->attr.mode & EVENTFS_SAVE_UID))
|
||||
inode->i_uid = ei->attr.uid;
|
||||
@@ -265,7 +284,7 @@ static int eventfs_permission(struct mnt_idmap *idmap,
|
||||
return generic_permission(idmap, inode, mask);
|
||||
}
|
||||
|
||||
static const struct inode_operations eventfs_root_dir_inode_operations = {
|
||||
static const struct inode_operations eventfs_dir_inode_operations = {
|
||||
.lookup = eventfs_root_lookup,
|
||||
.setattr = eventfs_set_attr,
|
||||
.getattr = eventfs_get_attr,
|
||||
@@ -282,6 +301,35 @@ static const struct file_operations eventfs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
/*
|
||||
* On a remount of tracefs, if UID or GID options are set, then
|
||||
* the mount point inode permissions should be used.
|
||||
* Reset the saved permission flags appropriately.
|
||||
*/
|
||||
void eventfs_remount(struct tracefs_inode *ti, bool update_uid, bool update_gid)
|
||||
{
|
||||
struct eventfs_inode *ei = ti->private;
|
||||
|
||||
if (!ei)
|
||||
return;
|
||||
|
||||
if (update_uid)
|
||||
ei->attr.mode &= ~EVENTFS_SAVE_UID;
|
||||
|
||||
if (update_gid)
|
||||
ei->attr.mode &= ~EVENTFS_SAVE_GID;
|
||||
|
||||
if (!ei->entry_attrs)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < ei->nr_entries; i++) {
|
||||
if (update_uid)
|
||||
ei->entry_attrs[i].mode &= ~EVENTFS_SAVE_UID;
|
||||
if (update_gid)
|
||||
ei->entry_attrs[i].mode &= ~EVENTFS_SAVE_GID;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the evenfs_inode of the "events" directory */
|
||||
static struct eventfs_inode *eventfs_find_events(struct dentry *dentry)
|
||||
{
|
||||
@@ -304,7 +352,7 @@ static struct eventfs_inode *eventfs_find_events(struct dentry *dentry)
|
||||
// Walk upwards until you find the events inode
|
||||
} while (!ei->is_events);
|
||||
|
||||
update_top_events_attr(ei, dentry->d_sb);
|
||||
update_events_attr(ei, dentry->d_sb);
|
||||
|
||||
return ei;
|
||||
}
|
||||
@@ -410,7 +458,7 @@ static struct dentry *lookup_dir_entry(struct dentry *dentry,
|
||||
update_inode_attr(dentry, inode, &ei->attr,
|
||||
S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO);
|
||||
|
||||
inode->i_op = &eventfs_root_dir_inode_operations;
|
||||
inode->i_op = &eventfs_dir_inode_operations;
|
||||
inode->i_fop = &eventfs_file_operations;
|
||||
|
||||
/* All directories will have the same inode number */
|
||||
@@ -734,7 +782,7 @@ struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode
|
||||
|
||||
/* Was the parent freed? */
|
||||
if (list_empty(&ei->list)) {
|
||||
free_ei(ei);
|
||||
cleanup_ei(ei);
|
||||
ei = NULL;
|
||||
}
|
||||
return ei;
|
||||
@@ -781,6 +829,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
|
||||
// Note: we have a ref to the dentry from tracefs_start_creating()
|
||||
rei = get_root_inode(ei);
|
||||
rei->events_dir = dentry;
|
||||
rei->parent_inode = d_inode(dentry->d_sb->s_root);
|
||||
|
||||
ei->entries = entries;
|
||||
ei->nr_entries = size;
|
||||
@@ -790,29 +839,26 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
|
||||
uid = d_inode(dentry->d_parent)->i_uid;
|
||||
gid = d_inode(dentry->d_parent)->i_gid;
|
||||
|
||||
/*
|
||||
* If the events directory is of the top instance, then parent
|
||||
* is NULL. Set the attr.mode to reflect this and its permissions will
|
||||
* default to the tracefs root dentry.
|
||||
*/
|
||||
if (!parent)
|
||||
ei->attr.mode = EVENTFS_TOPLEVEL;
|
||||
|
||||
/* This is used as the default ownership of the files and directories */
|
||||
ei->attr.uid = uid;
|
||||
ei->attr.gid = gid;
|
||||
|
||||
/*
|
||||
* When the "events" directory is created, it takes on the
|
||||
* permissions of its parent. But can be reset on remount.
|
||||
*/
|
||||
ei->attr.mode |= EVENTFS_SAVE_UID | EVENTFS_SAVE_GID;
|
||||
|
||||
INIT_LIST_HEAD(&ei->children);
|
||||
INIT_LIST_HEAD(&ei->list);
|
||||
|
||||
ti = get_tracefs(inode);
|
||||
ti->flags |= TRACEFS_EVENT_INODE | TRACEFS_EVENT_TOP_INODE;
|
||||
ti->flags |= TRACEFS_EVENT_INODE;
|
||||
ti->private = ei;
|
||||
|
||||
inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
|
||||
inode->i_uid = uid;
|
||||
inode->i_gid = gid;
|
||||
inode->i_op = &eventfs_root_dir_inode_operations;
|
||||
inode->i_op = &eventfs_dir_inode_operations;
|
||||
inode->i_fop = &eventfs_file_operations;
|
||||
|
||||
dentry->d_fsdata = get_ei(ei);
|
||||
@@ -835,7 +881,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
|
||||
return ei;
|
||||
|
||||
fail:
|
||||
free_ei(ei);
|
||||
cleanup_ei(ei);
|
||||
tracefs_failed_creating(dentry);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
+89
-3
@@ -30,20 +30,47 @@ static struct vfsmount *tracefs_mount;
|
||||
static int tracefs_mount_count;
|
||||
static bool tracefs_registered;
|
||||
|
||||
/*
|
||||
* Keep track of all tracefs_inodes in order to update their
|
||||
* flags if necessary on a remount.
|
||||
*/
|
||||
static DEFINE_SPINLOCK(tracefs_inode_lock);
|
||||
static LIST_HEAD(tracefs_inodes);
|
||||
|
||||
static struct inode *tracefs_alloc_inode(struct super_block *sb)
|
||||
{
|
||||
struct tracefs_inode *ti;
|
||||
unsigned long flags;
|
||||
|
||||
ti = kmem_cache_alloc(tracefs_inode_cachep, GFP_KERNEL);
|
||||
if (!ti)
|
||||
return NULL;
|
||||
|
||||
spin_lock_irqsave(&tracefs_inode_lock, flags);
|
||||
list_add_rcu(&ti->list, &tracefs_inodes);
|
||||
spin_unlock_irqrestore(&tracefs_inode_lock, flags);
|
||||
|
||||
return &ti->vfs_inode;
|
||||
}
|
||||
|
||||
static void tracefs_free_inode_rcu(struct rcu_head *rcu)
|
||||
{
|
||||
struct tracefs_inode *ti;
|
||||
|
||||
ti = container_of(rcu, struct tracefs_inode, rcu);
|
||||
kmem_cache_free(tracefs_inode_cachep, ti);
|
||||
}
|
||||
|
||||
static void tracefs_free_inode(struct inode *inode)
|
||||
{
|
||||
kmem_cache_free(tracefs_inode_cachep, get_tracefs(inode));
|
||||
struct tracefs_inode *ti = get_tracefs(inode);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tracefs_inode_lock, flags);
|
||||
list_del_rcu(&ti->list);
|
||||
spin_unlock_irqrestore(&tracefs_inode_lock, flags);
|
||||
|
||||
call_rcu(&ti->rcu, tracefs_free_inode_rcu);
|
||||
}
|
||||
|
||||
static ssize_t default_read_file(struct file *file, char __user *buf,
|
||||
@@ -153,16 +180,39 @@ static void set_tracefs_inode_owner(struct inode *inode)
|
||||
{
|
||||
struct tracefs_inode *ti = get_tracefs(inode);
|
||||
struct inode *root_inode = ti->private;
|
||||
kuid_t uid;
|
||||
kgid_t gid;
|
||||
|
||||
uid = root_inode->i_uid;
|
||||
gid = root_inode->i_gid;
|
||||
|
||||
/*
|
||||
* If the root is not the mount point, then check the root's
|
||||
* permissions. If it was never set, then default to the
|
||||
* mount point.
|
||||
*/
|
||||
if (root_inode != d_inode(root_inode->i_sb->s_root)) {
|
||||
struct tracefs_inode *rti;
|
||||
|
||||
rti = get_tracefs(root_inode);
|
||||
root_inode = d_inode(root_inode->i_sb->s_root);
|
||||
|
||||
if (!(rti->flags & TRACEFS_UID_PERM_SET))
|
||||
uid = root_inode->i_uid;
|
||||
|
||||
if (!(rti->flags & TRACEFS_GID_PERM_SET))
|
||||
gid = root_inode->i_gid;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this inode has never been referenced, then update
|
||||
* the permissions to the superblock.
|
||||
*/
|
||||
if (!(ti->flags & TRACEFS_UID_PERM_SET))
|
||||
inode->i_uid = root_inode->i_uid;
|
||||
inode->i_uid = uid;
|
||||
|
||||
if (!(ti->flags & TRACEFS_GID_PERM_SET))
|
||||
inode->i_gid = root_inode->i_gid;
|
||||
inode->i_gid = gid;
|
||||
}
|
||||
|
||||
static int tracefs_permission(struct mnt_idmap *idmap,
|
||||
@@ -313,6 +363,8 @@ static int tracefs_apply_options(struct super_block *sb, bool remount)
|
||||
struct tracefs_fs_info *fsi = sb->s_fs_info;
|
||||
struct inode *inode = d_inode(sb->s_root);
|
||||
struct tracefs_mount_opts *opts = &fsi->mount_opts;
|
||||
struct tracefs_inode *ti;
|
||||
bool update_uid, update_gid;
|
||||
umode_t tmp_mode;
|
||||
|
||||
/*
|
||||
@@ -332,6 +384,25 @@ static int tracefs_apply_options(struct super_block *sb, bool remount)
|
||||
if (!remount || opts->opts & BIT(Opt_gid))
|
||||
inode->i_gid = opts->gid;
|
||||
|
||||
if (remount && (opts->opts & BIT(Opt_uid) || opts->opts & BIT(Opt_gid))) {
|
||||
|
||||
update_uid = opts->opts & BIT(Opt_uid);
|
||||
update_gid = opts->opts & BIT(Opt_gid);
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(ti, &tracefs_inodes, list) {
|
||||
if (update_uid)
|
||||
ti->flags &= ~TRACEFS_UID_PERM_SET;
|
||||
|
||||
if (update_gid)
|
||||
ti->flags &= ~TRACEFS_GID_PERM_SET;
|
||||
|
||||
if (ti->flags & TRACEFS_EVENT_INODE)
|
||||
eventfs_remount(ti, update_uid, update_gid);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -398,7 +469,22 @@ static int tracefs_d_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
return !(ei && ei->is_freed);
|
||||
}
|
||||
|
||||
static void tracefs_d_iput(struct dentry *dentry, struct inode *inode)
|
||||
{
|
||||
struct tracefs_inode *ti = get_tracefs(inode);
|
||||
|
||||
/*
|
||||
* This inode is being freed and cannot be used for
|
||||
* eventfs. Clear the flag so that it doesn't call into
|
||||
* eventfs during the remount flag updates. The eventfs_inode
|
||||
* gets freed after an RCU cycle, so the content will still
|
||||
* be safe if the iteration is going on now.
|
||||
*/
|
||||
ti->flags &= ~TRACEFS_EVENT_INODE;
|
||||
}
|
||||
|
||||
static const struct dentry_operations tracefs_dentry_operations = {
|
||||
.d_iput = tracefs_d_iput,
|
||||
.d_revalidate = tracefs_d_revalidate,
|
||||
.d_release = tracefs_d_release,
|
||||
};
|
||||
|
||||
@@ -4,15 +4,18 @@
|
||||
|
||||
enum {
|
||||
TRACEFS_EVENT_INODE = BIT(1),
|
||||
TRACEFS_EVENT_TOP_INODE = BIT(2),
|
||||
TRACEFS_GID_PERM_SET = BIT(3),
|
||||
TRACEFS_UID_PERM_SET = BIT(4),
|
||||
TRACEFS_INSTANCE_INODE = BIT(5),
|
||||
TRACEFS_GID_PERM_SET = BIT(2),
|
||||
TRACEFS_UID_PERM_SET = BIT(3),
|
||||
TRACEFS_INSTANCE_INODE = BIT(4),
|
||||
};
|
||||
|
||||
struct tracefs_inode {
|
||||
struct inode vfs_inode;
|
||||
union {
|
||||
struct inode vfs_inode;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
/* The below gets initialized with memset_after(ti, 0, vfs_inode) */
|
||||
struct list_head list;
|
||||
unsigned long flags;
|
||||
void *private;
|
||||
};
|
||||
@@ -73,6 +76,7 @@ struct dentry *tracefs_end_creating(struct dentry *dentry);
|
||||
struct dentry *tracefs_failed_creating(struct dentry *dentry);
|
||||
struct inode *tracefs_get_inode(struct super_block *sb);
|
||||
|
||||
void eventfs_remount(struct tracefs_inode *ti, bool update_uid, bool update_gid);
|
||||
void eventfs_d_release(struct dentry *dentry);
|
||||
|
||||
#endif /* _TRACEFS_INTERNAL_H */
|
||||
|
||||
@@ -1230,6 +1230,7 @@ int regmap_multi_reg_write_bypassed(struct regmap *map,
|
||||
int regmap_raw_write_async(struct regmap *map, unsigned int reg,
|
||||
const void *val, size_t val_len);
|
||||
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);
|
||||
int regmap_read_bypassed(struct regmap *map, unsigned int reg, unsigned int *val);
|
||||
int regmap_raw_read(struct regmap *map, unsigned int reg,
|
||||
void *val, size_t val_len);
|
||||
int regmap_noinc_read(struct regmap *map, unsigned int reg,
|
||||
@@ -1739,6 +1740,13 @@ static inline int regmap_read(struct regmap *map, unsigned int reg,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int regmap_read_bypassed(struct regmap *map, unsigned int reg,
|
||||
unsigned int *val)
|
||||
{
|
||||
WARN_ONCE(1, "regmap API is disabled");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int regmap_raw_read(struct regmap *map, unsigned int reg,
|
||||
void *val, size_t val_len)
|
||||
{
|
||||
|
||||
@@ -62,6 +62,8 @@ struct eventfs_file;
|
||||
typedef int (*eventfs_callback)(const char *name, umode_t *mode, void **data,
|
||||
const struct file_operations **fops);
|
||||
|
||||
typedef void (*eventfs_release)(const char *name, void *data);
|
||||
|
||||
/**
|
||||
* struct eventfs_entry - dynamically created eventfs file call back handler
|
||||
* @name: Then name of the dynamic file in an eventfs directory
|
||||
@@ -72,6 +74,7 @@ typedef int (*eventfs_callback)(const char *name, umode_t *mode, void **data,
|
||||
struct eventfs_entry {
|
||||
const char *name;
|
||||
eventfs_callback callback;
|
||||
eventfs_release release;
|
||||
};
|
||||
|
||||
struct eventfs_inode;
|
||||
|
||||
@@ -267,6 +267,7 @@ struct cs35l56_base {
|
||||
bool fw_patched;
|
||||
bool secured;
|
||||
bool can_hibernate;
|
||||
bool fw_owns_asp1;
|
||||
bool cal_data_valid;
|
||||
s8 cal_index;
|
||||
struct cirrus_amp_cal_data cal_data;
|
||||
@@ -283,6 +284,7 @@ extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
|
||||
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];
|
||||
|
||||
int cs35l56_set_patch(struct cs35l56_base *cs35l56_base);
|
||||
int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base);
|
||||
int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base);
|
||||
int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command);
|
||||
int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base);
|
||||
|
||||
@@ -1684,8 +1684,8 @@ struct snd_emu1010 {
|
||||
unsigned int clock_fallback;
|
||||
unsigned int optical_in; /* 0:SPDIF, 1:ADAT */
|
||||
unsigned int optical_out; /* 0:SPDIF, 1:ADAT */
|
||||
struct work_struct firmware_work;
|
||||
struct work_struct clock_work;
|
||||
struct work_struct work;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
struct snd_emu10k1 {
|
||||
@@ -1834,6 +1834,9 @@ unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg,
|
||||
void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data);
|
||||
int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data);
|
||||
int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
|
||||
static inline void snd_emu1010_fpga_lock(struct snd_emu10k1 *emu) { mutex_lock(&emu->emu1010.lock); };
|
||||
static inline void snd_emu1010_fpga_unlock(struct snd_emu10k1 *emu) { mutex_unlock(&emu->emu1010.lock); };
|
||||
void snd_emu1010_fpga_write_lock(struct snd_emu10k1 *emu, u32 reg, u32 value);
|
||||
void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value);
|
||||
void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value);
|
||||
void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src);
|
||||
|
||||
@@ -1798,6 +1798,7 @@ static int rmem_swiotlb_device_init(struct reserved_mem *rmem,
|
||||
mem->for_alloc = true;
|
||||
#ifdef CONFIG_SWIOTLB_DYNAMIC
|
||||
spin_lock_init(&mem->lock);
|
||||
INIT_LIST_HEAD_RCU(&mem->pools);
|
||||
#endif
|
||||
add_mem_pool(mem, pool);
|
||||
|
||||
|
||||
@@ -2552,6 +2552,14 @@ static int event_callback(const char *name, umode_t *mode, void **data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The file is incremented on creation and freeing the enable file decrements it */
|
||||
static void event_release(const char *name, void *data)
|
||||
{
|
||||
struct trace_event_file *file = data;
|
||||
|
||||
event_file_put(file);
|
||||
}
|
||||
|
||||
static int
|
||||
event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file)
|
||||
{
|
||||
@@ -2566,6 +2574,7 @@ event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file)
|
||||
{
|
||||
.name = "enable",
|
||||
.callback = event_callback,
|
||||
.release = event_release,
|
||||
},
|
||||
{
|
||||
.name = "filter",
|
||||
@@ -2634,6 +2643,9 @@ event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Gets decremented on freeing of the "enable" file */
|
||||
event_file_get(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -557,9 +557,32 @@ static const struct config_entry *snd_intel_dsp_find_config
|
||||
if (table->codec_hid) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < table->codec_hid->num_codecs; i++)
|
||||
if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1))
|
||||
for (i = 0; i < table->codec_hid->num_codecs; i++) {
|
||||
struct nhlt_acpi_table *nhlt;
|
||||
bool ssp_found = false;
|
||||
|
||||
if (!acpi_dev_present(table->codec_hid->codecs[i], NULL, -1))
|
||||
continue;
|
||||
|
||||
nhlt = intel_nhlt_init(&pci->dev);
|
||||
if (!nhlt) {
|
||||
dev_warn(&pci->dev, "%s: NHLT table not found, skipped HID %s\n",
|
||||
__func__, table->codec_hid->codecs[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_SSP) &&
|
||||
intel_nhlt_ssp_endpoint_mask(nhlt, NHLT_DEVICE_I2S))
|
||||
ssp_found = true;
|
||||
|
||||
intel_nhlt_free(nhlt);
|
||||
|
||||
if (ssp_found)
|
||||
break;
|
||||
|
||||
dev_warn(&pci->dev, "%s: no valid SSP found for HID %s, skipped\n",
|
||||
__func__, table->codec_hid->codecs[i]);
|
||||
}
|
||||
if (i == table->codec_hid->num_codecs)
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ static bool is_link_enabled(struct fwnode_handle *fw_node, u8 idx)
|
||||
"intel-quirk-mask",
|
||||
&quirk_mask);
|
||||
|
||||
fwnode_handle_put(link);
|
||||
|
||||
if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -189,8 +189,7 @@ static int snd_emu10k1_suspend(struct device *dev)
|
||||
|
||||
emu->suspend = 1;
|
||||
|
||||
cancel_work_sync(&emu->emu1010.firmware_work);
|
||||
cancel_work_sync(&emu->emu1010.clock_work);
|
||||
cancel_work_sync(&emu->emu1010.work);
|
||||
|
||||
snd_ac97_suspend(emu->ac97);
|
||||
|
||||
|
||||
@@ -732,69 +732,67 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, int dock,
|
||||
return snd_emu1010_load_firmware_entry(emu, *fw);
|
||||
}
|
||||
|
||||
static void emu1010_firmware_work(struct work_struct *work)
|
||||
static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
|
||||
{
|
||||
struct snd_emu10k1 *emu;
|
||||
u32 tmp, tmp2, reg;
|
||||
u32 tmp, tmp2;
|
||||
int err;
|
||||
|
||||
emu = container_of(work, struct snd_emu10k1,
|
||||
emu1010.firmware_work);
|
||||
if (emu->card->shutdown)
|
||||
// The docking events clearly arrive prematurely - while the
|
||||
// Dock's FPGA seems to be successfully programmed, the Dock
|
||||
// fails to initialize subsequently if we don't give it some
|
||||
// time to "warm up" here.
|
||||
msleep(200);
|
||||
|
||||
dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware\n");
|
||||
/* Return to Audio Dock programming mode */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
|
||||
EMU_HANA_FPGA_CONFIG_AUDIODOCK);
|
||||
err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
|
||||
if (err < 0)
|
||||
return;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
if (emu->suspend)
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
|
||||
|
||||
snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
|
||||
dev_dbg(emu->card->dev, "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
|
||||
if ((tmp & 0x1f) != 0x15) {
|
||||
/* FPGA failed to be programmed */
|
||||
dev_err(emu->card->dev,
|
||||
"emu1010: Loading Audio Dock Firmware failed, reg = 0x%x\n",
|
||||
tmp);
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
dev_info(emu->card->dev, "emu1010: Audio Dock Firmware loaded\n");
|
||||
|
||||
snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
|
||||
snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
|
||||
dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2);
|
||||
|
||||
/* Allow DLL to settle, to sync clocking between 1010 and Dock */
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
static void emu1010_dock_event(struct snd_emu10k1 *emu)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */
|
||||
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
|
||||
/* Audio Dock attached */
|
||||
/* Return to Audio Dock programming mode */
|
||||
dev_info(emu->card->dev,
|
||||
"emu1010: Loading Audio Dock Firmware\n");
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
|
||||
EMU_HANA_FPGA_CONFIG_AUDIODOCK);
|
||||
err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
|
||||
if (err < 0)
|
||||
return;
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
|
||||
snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
|
||||
dev_info(emu->card->dev,
|
||||
"emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
|
||||
if ((tmp & 0x1f) != 0x15) {
|
||||
/* FPGA failed to be programmed */
|
||||
dev_info(emu->card->dev,
|
||||
"emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n",
|
||||
tmp);
|
||||
return;
|
||||
}
|
||||
dev_info(emu->card->dev,
|
||||
"emu1010: Audio Dock Firmware loaded\n");
|
||||
snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
|
||||
snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
|
||||
dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2);
|
||||
/* Sync clocking between 1010 and Dock */
|
||||
/* Allow DLL to settle */
|
||||
msleep(10);
|
||||
snd_emu1010_load_dock_firmware(emu);
|
||||
/* Unmute all. Default is muted after a firmware load */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
|
||||
} else if (!(reg & EMU_HANA_OPTION_DOCK_ONLINE)) {
|
||||
/* Audio Dock removed */
|
||||
dev_info(emu->card->dev, "emu1010: Audio Dock detached\n");
|
||||
/* The hardware auto-mutes all, so we unmute again */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
|
||||
}
|
||||
}
|
||||
|
||||
static void emu1010_clock_work(struct work_struct *work)
|
||||
static void emu1010_clock_event(struct snd_emu10k1 *emu)
|
||||
{
|
||||
struct snd_emu10k1 *emu;
|
||||
struct snd_ctl_elem_id id;
|
||||
|
||||
emu = container_of(work, struct snd_emu10k1,
|
||||
emu1010.clock_work);
|
||||
if (emu->card->shutdown)
|
||||
return;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
if (emu->suspend)
|
||||
return;
|
||||
#endif
|
||||
|
||||
spin_lock_irq(&emu->reg_lock);
|
||||
// This is the only thing that can actually happen.
|
||||
emu->emu1010.clock_source = emu->emu1010.clock_fallback;
|
||||
@@ -805,21 +803,44 @@ static void emu1010_clock_work(struct work_struct *work)
|
||||
snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
|
||||
}
|
||||
|
||||
static void emu1010_interrupt(struct snd_emu10k1 *emu)
|
||||
static void emu1010_work(struct work_struct *work)
|
||||
{
|
||||
struct snd_emu10k1 *emu;
|
||||
u32 sts;
|
||||
|
||||
emu = container_of(work, struct snd_emu10k1, emu1010.work);
|
||||
if (emu->card->shutdown)
|
||||
return;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
if (emu->suspend)
|
||||
return;
|
||||
#endif
|
||||
|
||||
snd_emu1010_fpga_lock(emu);
|
||||
|
||||
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts);
|
||||
if (sts & EMU_HANA_IRQ_DOCK_LOST) {
|
||||
/* Audio Dock removed */
|
||||
dev_info(emu->card->dev, "emu1010: Audio Dock detached\n");
|
||||
/* The hardware auto-mutes all, so we unmute again */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
|
||||
} else if (sts & EMU_HANA_IRQ_DOCK) {
|
||||
schedule_work(&emu->emu1010.firmware_work);
|
||||
}
|
||||
|
||||
// The distinction of the IRQ status bits is unreliable,
|
||||
// so we dispatch later based on option card status.
|
||||
if (sts & (EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST))
|
||||
emu1010_dock_event(emu);
|
||||
|
||||
if (sts & EMU_HANA_IRQ_WCLK_CHANGED)
|
||||
schedule_work(&emu->emu1010.clock_work);
|
||||
emu1010_clock_event(emu);
|
||||
|
||||
snd_emu1010_fpga_unlock(emu);
|
||||
}
|
||||
|
||||
static void emu1010_interrupt(struct snd_emu10k1 *emu)
|
||||
{
|
||||
// We get an interrupt on each GPIO input pin change, but we
|
||||
// care only about the ones triggered by the dedicated pin.
|
||||
u16 sts = inw(emu->port + A_GPIO);
|
||||
u16 bit = emu->card_capabilities->ca0108_chip ? 0x2000 : 0x8000;
|
||||
if (!(sts & bit))
|
||||
return;
|
||||
|
||||
schedule_work(&emu->emu1010.work);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -841,6 +862,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
|
||||
* Proper init follows in snd_emu10k1_init(). */
|
||||
outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
|
||||
|
||||
snd_emu1010_fpga_lock(emu);
|
||||
|
||||
/* Disable 48Volt power to Audio Dock */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
|
||||
|
||||
@@ -866,7 +889,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
|
||||
err = snd_emu1010_load_firmware(emu, 0, &emu->firmware);
|
||||
if (err < 0) {
|
||||
dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n");
|
||||
return err;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
|
||||
@@ -876,7 +899,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
|
||||
dev_info(emu->card->dev,
|
||||
"emu1010: Loading Hana Firmware file failed, reg = 0x%x\n",
|
||||
reg);
|
||||
return -ENODEV;
|
||||
err = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev_info(emu->card->dev, "emu1010: Hana Firmware loaded\n");
|
||||
@@ -889,7 +913,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
|
||||
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®);
|
||||
dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg);
|
||||
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE)
|
||||
schedule_work(&emu->emu1010.firmware_work);
|
||||
snd_emu1010_load_dock_firmware(emu);
|
||||
if (emu->card_capabilities->no_adat) {
|
||||
emu->emu1010.optical_in = 0; /* IN_SPDIF */
|
||||
emu->emu1010.optical_out = 0; /* OUT_SPDIF */
|
||||
@@ -936,7 +960,9 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
|
||||
// so it is safe to simply enable the outputs.
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
snd_emu1010_fpga_unlock(emu);
|
||||
return err;
|
||||
}
|
||||
/*
|
||||
* Create the EMU10K1 instance
|
||||
@@ -958,10 +984,10 @@ static void snd_emu10k1_free(struct snd_card *card)
|
||||
}
|
||||
if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) {
|
||||
/* Disable 48Volt power to Audio Dock */
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
|
||||
snd_emu1010_fpga_write_lock(emu, EMU_HANA_DOCK_PWR, 0);
|
||||
}
|
||||
cancel_work_sync(&emu->emu1010.firmware_work);
|
||||
cancel_work_sync(&emu->emu1010.clock_work);
|
||||
cancel_work_sync(&emu->emu1010.work);
|
||||
mutex_destroy(&emu->emu1010.lock);
|
||||
release_firmware(emu->firmware);
|
||||
release_firmware(emu->dock_fw);
|
||||
snd_util_memhdr_free(emu->memhdr);
|
||||
@@ -1540,8 +1566,8 @@ int snd_emu10k1_create(struct snd_card *card,
|
||||
emu->irq = -1;
|
||||
emu->synth = NULL;
|
||||
emu->get_synth_voice = NULL;
|
||||
INIT_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work);
|
||||
INIT_WORK(&emu->emu1010.clock_work, emu1010_clock_work);
|
||||
INIT_WORK(&emu->emu1010.work, emu1010_work);
|
||||
mutex_init(&emu->emu1010.lock);
|
||||
/* read revision & serial */
|
||||
emu->revision = pci->revision;
|
||||
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
|
||||
|
||||
@@ -661,7 +661,9 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol,
|
||||
change = (emu->emu1010.output_source[channel] != val);
|
||||
if (change) {
|
||||
emu->emu1010.output_source[channel] = val;
|
||||
snd_emu1010_fpga_lock(emu);
|
||||
snd_emu1010_output_source_apply(emu, channel, val);
|
||||
snd_emu1010_fpga_unlock(emu);
|
||||
}
|
||||
return change;
|
||||
}
|
||||
@@ -705,7 +707,9 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol,
|
||||
change = (emu->emu1010.input_source[channel] != val);
|
||||
if (change) {
|
||||
emu->emu1010.input_source[channel] = val;
|
||||
snd_emu1010_fpga_lock(emu);
|
||||
snd_emu1010_input_source_apply(emu, channel, val);
|
||||
snd_emu1010_fpga_unlock(emu);
|
||||
}
|
||||
return change;
|
||||
}
|
||||
@@ -774,7 +778,7 @@ static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct
|
||||
cache = cache & ~mask;
|
||||
change = (cache != emu->emu1010.adc_pads);
|
||||
if (change) {
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache );
|
||||
snd_emu1010_fpga_write_lock(emu, EMU_HANA_ADC_PADS, cache );
|
||||
emu->emu1010.adc_pads = cache;
|
||||
}
|
||||
|
||||
@@ -832,7 +836,7 @@ static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct
|
||||
cache = cache & ~mask;
|
||||
change = (cache != emu->emu1010.dac_pads);
|
||||
if (change) {
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache );
|
||||
snd_emu1010_fpga_write_lock(emu, EMU_HANA_DAC_PADS, cache );
|
||||
emu->emu1010.dac_pads = cache;
|
||||
}
|
||||
|
||||
@@ -980,6 +984,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
|
||||
val = ucontrol->value.enumerated.item[0] ;
|
||||
if (val >= emu_ci->num)
|
||||
return -EINVAL;
|
||||
snd_emu1010_fpga_lock(emu);
|
||||
spin_lock_irq(&emu->reg_lock);
|
||||
change = (emu->emu1010.clock_source != val);
|
||||
if (change) {
|
||||
@@ -996,6 +1001,7 @@ static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol,
|
||||
} else {
|
||||
spin_unlock_irq(&emu->reg_lock);
|
||||
}
|
||||
snd_emu1010_fpga_unlock(emu);
|
||||
return change;
|
||||
}
|
||||
|
||||
@@ -1041,7 +1047,7 @@ static int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol,
|
||||
change = (emu->emu1010.clock_fallback != val);
|
||||
if (change) {
|
||||
emu->emu1010.clock_fallback = val;
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 1 - val);
|
||||
snd_emu1010_fpga_write_lock(emu, EMU_HANA_DEFCLOCK, 1 - val);
|
||||
}
|
||||
return change;
|
||||
}
|
||||
@@ -1093,7 +1099,7 @@ static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol,
|
||||
emu->emu1010.optical_out = val;
|
||||
tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
|
||||
(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
|
||||
snd_emu1010_fpga_write_lock(emu, EMU_HANA_OPTICAL_TYPE, tmp);
|
||||
}
|
||||
return change;
|
||||
}
|
||||
@@ -1144,7 +1150,7 @@ static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol,
|
||||
emu->emu1010.optical_in = val;
|
||||
tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
|
||||
(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
|
||||
snd_emu1010_fpga_write_lock(emu, EMU_HANA_OPTICAL_TYPE, tmp);
|
||||
}
|
||||
return change;
|
||||
}
|
||||
@@ -2323,7 +2329,9 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu,
|
||||
for (i = 0; i < emu_ri->n_outs; i++)
|
||||
emu->emu1010.output_source[i] =
|
||||
emu1010_map_source(emu_ri, emu_ri->out_dflts[i]);
|
||||
snd_emu1010_fpga_lock(emu);
|
||||
snd_emu1010_apply_sources(emu);
|
||||
snd_emu1010_fpga_unlock(emu);
|
||||
|
||||
kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu);
|
||||
err = snd_ctl_add(card, kctl);
|
||||
|
||||
@@ -165,6 +165,8 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry,
|
||||
u32 value2;
|
||||
|
||||
if (emu->card_capabilities->emu_model) {
|
||||
snd_emu1010_fpga_lock(emu);
|
||||
|
||||
// This represents the S/PDIF lock status on 0404b, which is
|
||||
// kinda weird and unhelpful, because monitoring it via IRQ is
|
||||
// impractical (one gets an IRQ flood as long as it is desynced).
|
||||
@@ -197,6 +199,8 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry,
|
||||
snd_iprintf(buffer, "\nS/PDIF mode: %s%s\n",
|
||||
value & EMU_HANA_SPDIF_MODE_RX_PRO ? "professional" : "consumer",
|
||||
value & EMU_HANA_SPDIF_MODE_RX_NOCOPY ? ", no copy" : "");
|
||||
|
||||
snd_emu1010_fpga_unlock(emu);
|
||||
} else {
|
||||
snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS);
|
||||
snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS);
|
||||
@@ -458,6 +462,9 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry,
|
||||
struct snd_emu10k1 *emu = entry->private_data;
|
||||
u32 value;
|
||||
int i;
|
||||
|
||||
snd_emu1010_fpga_lock(emu);
|
||||
|
||||
snd_iprintf(buffer, "EMU1010 Registers:\n\n");
|
||||
|
||||
for(i = 0; i < 0x40; i+=1) {
|
||||
@@ -496,6 +503,8 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry,
|
||||
snd_emu_proc_emu1010_link_read(emu, buffer, 0x701);
|
||||
}
|
||||
}
|
||||
|
||||
snd_emu1010_fpga_unlock(emu);
|
||||
}
|
||||
|
||||
static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry,
|
||||
|
||||
+22
-29
@@ -285,24 +285,33 @@ static void snd_emu1010_fpga_write_locked(struct snd_emu10k1 *emu, u32 reg, u32
|
||||
outw(value, emu->port + A_GPIO);
|
||||
udelay(10);
|
||||
outw(value | 0x80 , emu->port + A_GPIO); /* High bit clocks the value into the fpga. */
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&emu->emu_lock, flags);
|
||||
if (snd_BUG_ON(!mutex_is_locked(&emu->emu1010.lock)))
|
||||
return;
|
||||
snd_emu1010_fpga_write_locked(emu, reg, value);
|
||||
spin_unlock_irqrestore(&emu->emu_lock, flags);
|
||||
}
|
||||
|
||||
static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 *value)
|
||||
void snd_emu1010_fpga_write_lock(struct snd_emu10k1 *emu, u32 reg, u32 value)
|
||||
{
|
||||
snd_emu1010_fpga_lock(emu);
|
||||
snd_emu1010_fpga_write_locked(emu, reg, value);
|
||||
snd_emu1010_fpga_unlock(emu);
|
||||
}
|
||||
|
||||
void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value)
|
||||
{
|
||||
// The higest input pin is used as the designated interrupt trigger,
|
||||
// so it needs to be masked out.
|
||||
// But note that any other input pin change will also cause an IRQ,
|
||||
// so using this function often causes an IRQ as a side effect.
|
||||
u32 mask = emu->card_capabilities->ca0108_chip ? 0x1f : 0x7f;
|
||||
|
||||
if (snd_BUG_ON(!mutex_is_locked(&emu->emu1010.lock)))
|
||||
return;
|
||||
if (snd_BUG_ON(reg > 0x3f))
|
||||
return;
|
||||
reg += 0x40; /* 0x40 upwards are registers. */
|
||||
@@ -313,47 +322,31 @@ static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 *
|
||||
*value = ((inw(emu->port + A_GPIO) >> 8) & mask);
|
||||
}
|
||||
|
||||
void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&emu->emu_lock, flags);
|
||||
snd_emu1010_fpga_read_locked(emu, reg, value);
|
||||
spin_unlock_irqrestore(&emu->emu_lock, flags);
|
||||
}
|
||||
|
||||
/* Each Destination has one and only one Source,
|
||||
* but one Source can feed any number of Destinations simultaneously.
|
||||
*/
|
||||
void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (snd_BUG_ON(dst & ~0x71f))
|
||||
return;
|
||||
if (snd_BUG_ON(src & ~0x71f))
|
||||
return;
|
||||
spin_lock_irqsave(&emu->emu_lock, flags);
|
||||
snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTHI, dst >> 8);
|
||||
snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTLO, dst & 0x1f);
|
||||
snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCHI, src >> 8);
|
||||
snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCLO, src & 0x1f);
|
||||
spin_unlock_irqrestore(&emu->emu_lock, flags);
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DESTHI, dst >> 8);
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DESTLO, dst & 0x1f);
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_SRCHI, src >> 8);
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_SRCLO, src & 0x1f);
|
||||
}
|
||||
|
||||
u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 hi, lo;
|
||||
|
||||
if (snd_BUG_ON(dst & ~0x71f))
|
||||
return 0;
|
||||
spin_lock_irqsave(&emu->emu_lock, flags);
|
||||
snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTHI, dst >> 8);
|
||||
snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTLO, dst & 0x1f);
|
||||
snd_emu1010_fpga_read_locked(emu, EMU_HANA_SRCHI, &hi);
|
||||
snd_emu1010_fpga_read_locked(emu, EMU_HANA_SRCLO, &lo);
|
||||
spin_unlock_irqrestore(&emu->emu_lock, flags);
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DESTHI, dst >> 8);
|
||||
snd_emu1010_fpga_write(emu, EMU_HANA_DESTLO, dst & 0x1f);
|
||||
snd_emu1010_fpga_read(emu, EMU_HANA_SRCHI, &hi);
|
||||
snd_emu1010_fpga_read(emu, EMU_HANA_SRCLO, &lo);
|
||||
return (hi << 8) | lo;
|
||||
}
|
||||
|
||||
|
||||
@@ -644,6 +644,8 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
|
||||
ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
|
||||
if (ret)
|
||||
goto err_powered_up;
|
||||
|
||||
regcache_cache_only(cs35l56->base.regmap, false);
|
||||
}
|
||||
|
||||
/* Disable auto-hibernate so that runtime_pm has control */
|
||||
@@ -1002,6 +1004,8 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
regcache_cache_only(cs35l56->base.regmap, false);
|
||||
|
||||
ret = cs35l56_set_patch(&cs35l56->base);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@@ -920,6 +920,8 @@ static void alc_pre_init(struct hda_codec *codec)
|
||||
((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME)
|
||||
#define is_s4_resume(codec) \
|
||||
((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE)
|
||||
#define is_s4_suspend(codec) \
|
||||
((codec)->core.dev.power.power_state.event == PM_EVENT_FREEZE)
|
||||
|
||||
static int alc_init(struct hda_codec *codec)
|
||||
{
|
||||
@@ -7183,6 +7185,46 @@ static void alc245_fixup_hp_spectre_x360_eu0xxx(struct hda_codec *codec,
|
||||
alc245_fixup_hp_gpio_led(codec, fix, action);
|
||||
}
|
||||
|
||||
/*
|
||||
* ALC287 PCM hooks
|
||||
*/
|
||||
static void alc287_alc1318_playback_pcm_hook(struct hda_pcm_stream *hinfo,
|
||||
struct hda_codec *codec,
|
||||
struct snd_pcm_substream *substream,
|
||||
int action)
|
||||
{
|
||||
alc_write_coef_idx(codec, 0x10, 0x8806); /* Change MLK to GPIO3 */
|
||||
switch (action) {
|
||||
case HDA_GEN_PCM_ACT_OPEN:
|
||||
alc_write_coefex_idx(codec, 0x5a, 0x00, 0x954f); /* write gpio3 to high */
|
||||
break;
|
||||
case HDA_GEN_PCM_ACT_CLOSE:
|
||||
alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void __maybe_unused alc287_s4_power_gpio3_default(struct hda_codec *codec)
|
||||
{
|
||||
if (is_s4_suspend(codec)) {
|
||||
alc_write_coef_idx(codec, 0x10, 0x8806); /* Change MLK to GPIO3 */
|
||||
alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */
|
||||
}
|
||||
}
|
||||
|
||||
static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
struct alc_spec *spec = codec->spec;
|
||||
|
||||
if (action != HDA_FIXUP_ACT_PRE_PROBE)
|
||||
return;
|
||||
#ifdef CONFIG_PM
|
||||
spec->power_hook = alc287_s4_power_gpio3_default;
|
||||
#endif
|
||||
spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook;
|
||||
}
|
||||
|
||||
|
||||
enum {
|
||||
ALC269_FIXUP_GPIO2,
|
||||
@@ -7426,6 +7468,7 @@ enum {
|
||||
ALC287_FIXUP_YOGA7_14ITL_SPEAKERS,
|
||||
ALC298_FIXUP_LENOVO_C940_DUET7,
|
||||
ALC287_FIXUP_LENOVO_14IRP8_DUETITL,
|
||||
ALC287_FIXUP_LENOVO_LEGION_7,
|
||||
ALC287_FIXUP_13S_GEN2_SPEAKERS,
|
||||
ALC256_FIXUP_SET_COEF_DEFAULTS,
|
||||
ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
|
||||
@@ -7470,7 +7513,8 @@ enum {
|
||||
ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC,
|
||||
ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1,
|
||||
ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC,
|
||||
ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1
|
||||
ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1,
|
||||
ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318,
|
||||
};
|
||||
|
||||
/* A special fixup for Lenovo C940 and Yoga Duet 7;
|
||||
@@ -7510,6 +7554,23 @@ static void alc287_fixup_lenovo_14irp8_duetitl(struct hda_codec *codec,
|
||||
__snd_hda_apply_fixup(codec, id, action, 0);
|
||||
}
|
||||
|
||||
/* Another hilarious PCI SSID conflict with Lenovo Legion Pro 7 16ARX8H (with
|
||||
* TAS2781 codec) and Legion 7i 16IAX7 (with CS35L41 codec);
|
||||
* we apply a corresponding fixup depending on the codec SSID instead
|
||||
*/
|
||||
static void alc287_fixup_lenovo_legion_7(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix,
|
||||
int action)
|
||||
{
|
||||
int id;
|
||||
|
||||
if (codec->core.subsystem_id == 0x17aa38a8)
|
||||
id = ALC287_FIXUP_TAS2781_I2C; /* Legion Pro 7 16ARX8H */
|
||||
else
|
||||
id = ALC287_FIXUP_CS35L41_I2C_2; /* Legion 7i 16IAX7 */
|
||||
__snd_hda_apply_fixup(codec, id, action, 0);
|
||||
}
|
||||
|
||||
static const struct hda_fixup alc269_fixups[] = {
|
||||
[ALC269_FIXUP_GPIO2] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
@@ -9404,6 +9465,10 @@ static const struct hda_fixup alc269_fixups[] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc287_fixup_lenovo_14irp8_duetitl,
|
||||
},
|
||||
[ALC287_FIXUP_LENOVO_LEGION_7] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc287_fixup_lenovo_legion_7,
|
||||
},
|
||||
[ALC287_FIXUP_13S_GEN2_SPEAKERS] = {
|
||||
.type = HDA_FIXUP_VERBS,
|
||||
.v.verbs = (const struct hda_verb[]) {
|
||||
@@ -9726,6 +9791,12 @@ static const struct hda_fixup alc269_fixups[] = {
|
||||
.chained = true,
|
||||
.chain_id = ALC285_FIXUP_ASUS_GA403U,
|
||||
},
|
||||
[ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc287_fixup_lenovo_thinkpad_with_alc1318,
|
||||
.chained = true,
|
||||
.chain_id = ALC269_FIXUP_THINKPAD_ACPI
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
||||
@@ -9937,6 +10008,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
|
||||
SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
|
||||
SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
|
||||
SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
|
||||
@@ -10393,6 +10465,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x17aa, 0x2318, "Thinkpad Z13 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x2319, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x231a, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
|
||||
SND_PCI_QUIRK(0x17aa, 0x231e, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318),
|
||||
SND_PCI_QUIRK(0x17aa, 0x231f, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318),
|
||||
SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
|
||||
SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
|
||||
SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
|
||||
@@ -10422,7 +10496,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
||||
SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
|
||||
SND_PCI_QUIRK(0x17aa, 0x386f, "Legion 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7/7i", ALC287_FIXUP_LENOVO_LEGION_7),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3877, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x17aa, 0x3878, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
|
||||
@@ -430,6 +430,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "MRID6"),
|
||||
}
|
||||
},
|
||||
{
|
||||
.driver_data = &acp6x_card,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "MDC"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "Herbag_MDU"),
|
||||
}
|
||||
},
|
||||
{
|
||||
.driver_data = &acp6x_card,
|
||||
.matches = {
|
||||
|
||||
@@ -1094,6 +1094,7 @@ static int cs35l41_handle_pdata(struct device *dev, struct cs35l41_hw_cfg *hw_cf
|
||||
static int cs35l41_dsp_init(struct cs35l41_private *cs35l41)
|
||||
{
|
||||
struct wm_adsp *dsp;
|
||||
uint32_t dsp1rx5_src;
|
||||
int ret;
|
||||
|
||||
dsp = &cs35l41->dsp;
|
||||
@@ -1113,16 +1114,29 @@ static int cs35l41_dsp_init(struct cs35l41_private *cs35l41)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX5_SRC,
|
||||
CS35L41_INPUT_SRC_VPMON);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "Write INPUT_SRC_VPMON failed: %d\n", ret);
|
||||
switch (cs35l41->hw_cfg.bst_type) {
|
||||
case CS35L41_INT_BOOST:
|
||||
case CS35L41_SHD_BOOST_ACTV:
|
||||
dsp1rx5_src = CS35L41_INPUT_SRC_VPMON;
|
||||
break;
|
||||
case CS35L41_EXT_BOOST:
|
||||
case CS35L41_SHD_BOOST_PASS:
|
||||
dsp1rx5_src = CS35L41_INPUT_SRC_VBSTMON;
|
||||
break;
|
||||
default:
|
||||
dev_err(cs35l41->dev, "wm_halo_init failed - Invalid Boost Type: %d\n",
|
||||
cs35l41->hw_cfg.bst_type);
|
||||
goto err_dsp;
|
||||
}
|
||||
ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX6_SRC,
|
||||
CS35L41_INPUT_SRC_CLASSH);
|
||||
|
||||
ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX5_SRC, dsp1rx5_src);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "Write INPUT_SRC_CLASSH failed: %d\n", ret);
|
||||
dev_err(cs35l41->dev, "Write DSP1RX5_SRC: %d failed: %d\n", dsp1rx5_src, ret);
|
||||
goto err_dsp;
|
||||
}
|
||||
ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX6_SRC, CS35L41_INPUT_SRC_VBSTMON);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "Write CS35L41_INPUT_SRC_VBSTMON failed: %d\n", ret);
|
||||
goto err_dsp;
|
||||
}
|
||||
ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX7_SRC,
|
||||
|
||||
@@ -188,8 +188,6 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral)
|
||||
goto out;
|
||||
}
|
||||
|
||||
regcache_cache_only(cs35l56->base.regmap, false);
|
||||
|
||||
ret = cs35l56_init(cs35l56);
|
||||
if (ret < 0) {
|
||||
regcache_cache_only(cs35l56->base.regmap, true);
|
||||
|
||||
@@ -40,16 +40,11 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED);
|
||||
static const struct reg_default cs35l56_reg_defaults[] = {
|
||||
/* no defaults for OTP_MEM - first read populates cache */
|
||||
|
||||
{ CS35L56_ASP1_ENABLES1, 0x00000000 },
|
||||
{ CS35L56_ASP1_CONTROL1, 0x00000028 },
|
||||
{ CS35L56_ASP1_CONTROL2, 0x18180200 },
|
||||
{ CS35L56_ASP1_CONTROL3, 0x00000002 },
|
||||
{ CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 },
|
||||
{ CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 },
|
||||
{ CS35L56_ASP1_DATA_CONTROL1, 0x00000018 },
|
||||
{ CS35L56_ASP1_DATA_CONTROL5, 0x00000018 },
|
||||
|
||||
/* no defaults for ASP1TX mixer */
|
||||
/*
|
||||
* No defaults for ASP1 control or ASP1TX mixer. See
|
||||
* cs35l56_populate_asp1_register_defaults() and
|
||||
* cs35l56_sync_asp1_mixer_widgets_with_firmware().
|
||||
*/
|
||||
|
||||
{ CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
|
||||
{ CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
|
||||
@@ -210,6 +205,36 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
|
||||
}
|
||||
}
|
||||
|
||||
static const struct reg_sequence cs35l56_asp1_defaults[] = {
|
||||
REG_SEQ0(CS35L56_ASP1_ENABLES1, 0x00000000),
|
||||
REG_SEQ0(CS35L56_ASP1_CONTROL1, 0x00000028),
|
||||
REG_SEQ0(CS35L56_ASP1_CONTROL2, 0x18180200),
|
||||
REG_SEQ0(CS35L56_ASP1_CONTROL3, 0x00000002),
|
||||
REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL1, 0x03020100),
|
||||
REG_SEQ0(CS35L56_ASP1_FRAME_CONTROL5, 0x00020100),
|
||||
REG_SEQ0(CS35L56_ASP1_DATA_CONTROL1, 0x00000018),
|
||||
REG_SEQ0(CS35L56_ASP1_DATA_CONTROL5, 0x00000018),
|
||||
};
|
||||
|
||||
/*
|
||||
* The firmware can have control of the ASP so we don't provide regmap
|
||||
* with defaults for these registers, to prevent a regcache_sync() from
|
||||
* overwriting the firmware settings. But if the machine driver hooks up
|
||||
* the ASP it means the driver is taking control of the ASP, so then the
|
||||
* registers are populated with the defaults.
|
||||
*/
|
||||
int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base)
|
||||
{
|
||||
if (!cs35l56_base->fw_owns_asp1)
|
||||
return 0;
|
||||
|
||||
cs35l56_base->fw_owns_asp1 = false;
|
||||
|
||||
return regmap_multi_reg_write(cs35l56_base->regmap, cs35l56_asp1_defaults,
|
||||
ARRAY_SIZE(cs35l56_asp1_defaults));
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cs35l56_init_asp1_regs_for_driver_control, SND_SOC_CS35L56_SHARED);
|
||||
|
||||
/*
|
||||
* The firmware boot sequence can overwrite the ASP1 config registers so that
|
||||
* they don't match regmap's view of their values. Rewrite the values from the
|
||||
@@ -217,19 +242,15 @@ static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg)
|
||||
*/
|
||||
int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base)
|
||||
{
|
||||
struct reg_sequence asp1_regs[] = {
|
||||
{ .reg = CS35L56_ASP1_ENABLES1 },
|
||||
{ .reg = CS35L56_ASP1_CONTROL1 },
|
||||
{ .reg = CS35L56_ASP1_CONTROL2 },
|
||||
{ .reg = CS35L56_ASP1_CONTROL3 },
|
||||
{ .reg = CS35L56_ASP1_FRAME_CONTROL1 },
|
||||
{ .reg = CS35L56_ASP1_FRAME_CONTROL5 },
|
||||
{ .reg = CS35L56_ASP1_DATA_CONTROL1 },
|
||||
{ .reg = CS35L56_ASP1_DATA_CONTROL5 },
|
||||
};
|
||||
struct reg_sequence asp1_regs[ARRAY_SIZE(cs35l56_asp1_defaults)];
|
||||
int i, ret;
|
||||
|
||||
/* Read values from regmap cache into a write sequence */
|
||||
if (cs35l56_base->fw_owns_asp1)
|
||||
return 0;
|
||||
|
||||
memcpy(asp1_regs, cs35l56_asp1_defaults, sizeof(asp1_regs));
|
||||
|
||||
/* Read current values from regmap cache into the write sequence */
|
||||
for (i = 0; i < ARRAY_SIZE(asp1_regs); ++i) {
|
||||
ret = regmap_read(cs35l56_base->regmap, asp1_regs[i].reg, &asp1_regs[i].def);
|
||||
if (ret)
|
||||
@@ -307,10 +328,10 @@ int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base)
|
||||
reg = CS35L56_DSP1_HALO_STATE;
|
||||
|
||||
/*
|
||||
* This can't be a regmap_read_poll_timeout() because cs35l56 will NAK
|
||||
* I2C until it has booted which would terminate the poll
|
||||
* The regmap must remain in cache-only until the chip has
|
||||
* booted, so use a bypassed read of the status register.
|
||||
*/
|
||||
poll_ret = read_poll_timeout(regmap_read, read_ret,
|
||||
poll_ret = read_poll_timeout(regmap_read_bypassed, read_ret,
|
||||
(val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE),
|
||||
CS35L56_HALO_STATE_POLL_US,
|
||||
CS35L56_HALO_STATE_TIMEOUT_US,
|
||||
@@ -362,7 +383,8 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
|
||||
return;
|
||||
|
||||
cs35l56_wait_control_port_ready();
|
||||
regcache_cache_only(cs35l56_base->regmap, false);
|
||||
|
||||
/* Leave in cache-only. This will be revoked when the chip has rebooted. */
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, SND_SOC_CS35L56_SHARED);
|
||||
|
||||
@@ -577,14 +599,14 @@ int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_sou
|
||||
cs35l56_issue_wake_event(cs35l56_base);
|
||||
|
||||
out_sync:
|
||||
regcache_cache_only(cs35l56_base->regmap, false);
|
||||
|
||||
ret = cs35l56_wait_for_firmware_boot(cs35l56_base);
|
||||
if (ret) {
|
||||
dev_err(cs35l56_base->dev, "Hibernate wake failed: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
regcache_cache_only(cs35l56_base->regmap, false);
|
||||
|
||||
ret = cs35l56_mbox_send(cs35l56_base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
|
||||
if (ret)
|
||||
goto err;
|
||||
@@ -684,7 +706,7 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_calibration_controls, SND_SOC_CS35L56_SHARED);
|
||||
|
||||
int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base)
|
||||
{
|
||||
u64 silicon_uid;
|
||||
u64 silicon_uid = 0;
|
||||
int ret;
|
||||
|
||||
/* Driver can't apply calibration to a secured part, so skip */
|
||||
@@ -757,7 +779,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
|
||||
* devices so the REVID needs to be determined before waiting for the
|
||||
* firmware to boot.
|
||||
*/
|
||||
ret = regmap_read(cs35l56_base->regmap, CS35L56_REVID, &revid);
|
||||
ret = regmap_read_bypassed(cs35l56_base->regmap, CS35L56_REVID, &revid);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l56_base->dev, "Get Revision ID failed\n");
|
||||
return ret;
|
||||
@@ -768,7 +790,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read(cs35l56_base->regmap, CS35L56_DEVID, &devid);
|
||||
ret = regmap_read_bypassed(cs35l56_base->regmap, CS35L56_DEVID, &devid);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l56_base->dev, "Get Device ID failed\n");
|
||||
return ret;
|
||||
@@ -787,6 +809,9 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
|
||||
|
||||
cs35l56_base->type = devid & 0xFF;
|
||||
|
||||
/* Silicon is now identified and booted so exit cache-only */
|
||||
regcache_cache_only(cs35l56_base->regmap, false);
|
||||
|
||||
ret = regmap_read(cs35l56_base->regmap, CS35L56_DSP_RESTRICT_STS1, &secured);
|
||||
if (ret) {
|
||||
dev_err(cs35l56_base->dev, "Get Secure status failed\n");
|
||||
|
||||
@@ -454,9 +454,14 @@ static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int f
|
||||
{
|
||||
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
dev_dbg(cs35l56->base.dev, "%s: %#x\n", __func__, fmt);
|
||||
|
||||
ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBC_CFC:
|
||||
break;
|
||||
@@ -530,6 +535,11 @@ static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx
|
||||
unsigned int rx_mask, int slots, int slot_width)
|
||||
{
|
||||
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
|
||||
int ret;
|
||||
|
||||
ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((slots == 0) || (slot_width == 0)) {
|
||||
dev_dbg(cs35l56->base.dev, "tdm config cleared\n");
|
||||
@@ -578,6 +588,11 @@ static int cs35l56_asp_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
|
||||
unsigned int rate = params_rate(params);
|
||||
u8 asp_width, asp_wl;
|
||||
int ret;
|
||||
|
||||
ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
asp_wl = params_width(params);
|
||||
if (cs35l56->asp_slot_width)
|
||||
@@ -634,7 +649,11 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
|
||||
int freq_id;
|
||||
int freq_id, ret;
|
||||
|
||||
ret = cs35l56_init_asp1_regs_for_driver_control(&cs35l56->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (freq == 0) {
|
||||
cs35l56->sysclk_set = false;
|
||||
@@ -1341,6 +1360,7 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5
|
||||
"spk-id-gpios", ACPI_TYPE_PACKAGE, &obj);
|
||||
if (ret) {
|
||||
dev_dbg(cs35l56->base.dev, "Could not get spk-id-gpios package: %d\n", ret);
|
||||
fwnode_handle_put(af01_fwnode);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
@@ -1348,6 +1368,7 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5
|
||||
if (obj->package.count != 4) {
|
||||
dev_warn(cs35l56->base.dev, "Unexpected spk-id element count %d\n",
|
||||
obj->package.count);
|
||||
fwnode_handle_put(af01_fwnode);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
@@ -1362,6 +1383,7 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5
|
||||
*/
|
||||
ret = acpi_dev_add_driver_gpios(adev, cs35l56_af01_spkid_gpios_mapping);
|
||||
if (ret) {
|
||||
fwnode_handle_put(af01_fwnode);
|
||||
return dev_err_probe(cs35l56->base.dev, ret,
|
||||
"Failed to add gpio mapping to AF01\n");
|
||||
}
|
||||
@@ -1369,14 +1391,17 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5
|
||||
ret = devm_add_action_or_reset(cs35l56->base.dev,
|
||||
cs35l56_acpi_dev_release_driver_gpios,
|
||||
adev);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
fwnode_handle_put(af01_fwnode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(cs35l56->base.dev, "Added spk-id-gpios mapping to AF01\n");
|
||||
}
|
||||
|
||||
desc = fwnode_gpiod_get_index(af01_fwnode, "spk-id", 0, GPIOD_IN, NULL);
|
||||
if (IS_ERR(desc)) {
|
||||
fwnode_handle_put(af01_fwnode);
|
||||
ret = PTR_ERR(desc);
|
||||
return dev_err_probe(cs35l56->base.dev, ret, "Get GPIO from AF01 failed\n");
|
||||
}
|
||||
@@ -1385,9 +1410,12 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5
|
||||
gpiod_put(desc);
|
||||
|
||||
if (ret < 0) {
|
||||
fwnode_handle_put(af01_fwnode);
|
||||
dev_err_probe(cs35l56->base.dev, ret, "Error reading spk-id GPIO\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
fwnode_handle_put(af01_fwnode);
|
||||
|
||||
dev_info(cs35l56->base.dev, "Got spk-id from AF01\n");
|
||||
|
||||
@@ -1403,6 +1431,9 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
|
||||
cs35l56->base.cal_index = -1;
|
||||
cs35l56->speaker_id = -ENOENT;
|
||||
|
||||
/* Assume that the firmware owns ASP1 until we know different */
|
||||
cs35l56->base.fw_owns_asp1 = true;
|
||||
|
||||
dev_set_drvdata(cs35l56->base.dev, cs35l56);
|
||||
|
||||
cs35l56_fill_supply_names(cs35l56->supplies);
|
||||
@@ -1531,6 +1562,8 @@ post_soft_reset:
|
||||
return ret;
|
||||
|
||||
dev_dbg(cs35l56->base.dev, "Firmware rebooted after soft reset\n");
|
||||
|
||||
regcache_cache_only(cs35l56->base.regmap, false);
|
||||
}
|
||||
|
||||
/* Disable auto-hibernate so that runtime_pm has control */
|
||||
|
||||
@@ -671,8 +671,10 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev)
|
||||
return NULL;
|
||||
|
||||
aad_pdata = devm_kzalloc(dev, sizeof(*aad_pdata), GFP_KERNEL);
|
||||
if (!aad_pdata)
|
||||
if (!aad_pdata) {
|
||||
fwnode_handle_put(aad_np);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aad_pdata->irq = i2c->irq;
|
||||
|
||||
@@ -753,6 +755,8 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev)
|
||||
else
|
||||
aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1;
|
||||
|
||||
fwnode_handle_put(aad_np);
|
||||
|
||||
return aad_pdata;
|
||||
}
|
||||
|
||||
|
||||
@@ -444,6 +444,7 @@ struct rt5645_priv {
|
||||
struct regmap *regmap;
|
||||
struct i2c_client *i2c;
|
||||
struct gpio_desc *gpiod_hp_det;
|
||||
struct gpio_desc *gpiod_cbj_sleeve;
|
||||
struct snd_soc_jack *hp_jack;
|
||||
struct snd_soc_jack *mic_jack;
|
||||
struct snd_soc_jack *btn_jack;
|
||||
@@ -3186,6 +3187,9 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse
|
||||
regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2,
|
||||
RT5645_CBJ_MN_JD, 0);
|
||||
|
||||
if (rt5645->gpiod_cbj_sleeve)
|
||||
gpiod_set_value(rt5645->gpiod_cbj_sleeve, 1);
|
||||
|
||||
msleep(600);
|
||||
regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val);
|
||||
val &= 0x7;
|
||||
@@ -3202,6 +3206,8 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse
|
||||
snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
|
||||
snd_soc_dapm_sync(dapm);
|
||||
rt5645->jack_type = SND_JACK_HEADPHONE;
|
||||
if (rt5645->gpiod_cbj_sleeve)
|
||||
gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0);
|
||||
}
|
||||
if (rt5645->pdata.level_trigger_irq)
|
||||
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
|
||||
@@ -3229,6 +3235,9 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse
|
||||
if (rt5645->pdata.level_trigger_irq)
|
||||
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
|
||||
RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
|
||||
|
||||
if (rt5645->gpiod_cbj_sleeve)
|
||||
gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0);
|
||||
}
|
||||
|
||||
return rt5645->jack_type;
|
||||
@@ -4012,6 +4021,16 @@ static int rt5645_i2c_probe(struct i2c_client *i2c)
|
||||
return ret;
|
||||
}
|
||||
|
||||
rt5645->gpiod_cbj_sleeve = devm_gpiod_get_optional(&i2c->dev, "cbj-sleeve",
|
||||
GPIOD_OUT_LOW);
|
||||
|
||||
if (IS_ERR(rt5645->gpiod_cbj_sleeve)) {
|
||||
ret = PTR_ERR(rt5645->gpiod_cbj_sleeve);
|
||||
dev_info(&i2c->dev, "failed to initialize gpiod, ret=%d\n", ret);
|
||||
if (ret != -ENOENT)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++)
|
||||
rt5645->supplies[i].supply = rt5645_supply_names[i];
|
||||
|
||||
@@ -4259,6 +4278,9 @@ static void rt5645_i2c_remove(struct i2c_client *i2c)
|
||||
cancel_delayed_work_sync(&rt5645->jack_detect_work);
|
||||
cancel_delayed_work_sync(&rt5645->rcclock_work);
|
||||
|
||||
if (rt5645->gpiod_cbj_sleeve)
|
||||
gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies);
|
||||
}
|
||||
|
||||
@@ -4274,6 +4296,9 @@ static void rt5645_i2c_shutdown(struct i2c_client *i2c)
|
||||
0);
|
||||
msleep(20);
|
||||
regmap_write(rt5645->regmap, RT5645_RESET, 0);
|
||||
|
||||
if (rt5645->gpiod_cbj_sleeve)
|
||||
gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0);
|
||||
}
|
||||
|
||||
static int __maybe_unused rt5645_sys_suspend(struct device *dev)
|
||||
|
||||
@@ -316,7 +316,7 @@ static int rt715_sdca_set_amp_gain_8ch_get(struct snd_kcontrol *kcontrol,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -17625, 375, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
|
||||
|
||||
static int rt715_sdca_get_volsw(struct snd_kcontrol *kcontrol,
|
||||
@@ -477,7 +477,7 @@ static const struct snd_kcontrol_new rt715_sdca_snd_controls[] = {
|
||||
RT715_SDCA_FU_VOL_CTRL, CH_01),
|
||||
SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
|
||||
RT715_SDCA_FU_VOL_CTRL, CH_02),
|
||||
0x2f, 0x7f, 0,
|
||||
0x2f, 0x3f, 0,
|
||||
rt715_sdca_set_amp_gain_get, rt715_sdca_set_amp_gain_put,
|
||||
in_vol_tlv),
|
||||
RT715_SDCA_EXT_TLV("FU02 Capture Volume",
|
||||
@@ -485,13 +485,13 @@ static const struct snd_kcontrol_new rt715_sdca_snd_controls[] = {
|
||||
RT715_SDCA_FU_VOL_CTRL, CH_01),
|
||||
rt715_sdca_set_amp_gain_4ch_get,
|
||||
rt715_sdca_set_amp_gain_4ch_put,
|
||||
in_vol_tlv, 4, 0x7f),
|
||||
in_vol_tlv, 4, 0x3f),
|
||||
RT715_SDCA_EXT_TLV("FU06 Capture Volume",
|
||||
SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL,
|
||||
RT715_SDCA_FU_VOL_CTRL, CH_01),
|
||||
rt715_sdca_set_amp_gain_4ch_get,
|
||||
rt715_sdca_set_amp_gain_4ch_put,
|
||||
in_vol_tlv, 4, 0x7f),
|
||||
in_vol_tlv, 4, 0x3f),
|
||||
/* MIC Boost Control */
|
||||
RT715_SDCA_BOOST_EXT_TLV("FU0E Boost",
|
||||
SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
|
||||
|
||||
@@ -111,6 +111,7 @@ static bool rt715_readable_register(struct device *dev, unsigned int reg)
|
||||
case 0x839d:
|
||||
case 0x83a7:
|
||||
case 0x83a9:
|
||||
case 0x752001:
|
||||
case 0x752039:
|
||||
return true;
|
||||
default:
|
||||
|
||||
@@ -1330,7 +1330,7 @@ static struct snd_soc_dai_driver rt722_sdca_dai[] = {
|
||||
.capture = {
|
||||
.stream_name = "DP6 DMic Capture",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.channels_max = 4,
|
||||
.rates = RT722_STEREO_RATES,
|
||||
.formats = RT722_FORMATS,
|
||||
},
|
||||
@@ -1439,9 +1439,12 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722)
|
||||
int loop_check, chk_cnt = 100, ret;
|
||||
unsigned int calib_status = 0;
|
||||
|
||||
/* Read eFuse */
|
||||
rt722_sdca_index_write(rt722, RT722_VENDOR_SPK_EFUSE, RT722_DC_CALIB_CTRL,
|
||||
0x4808);
|
||||
/* Config analog bias */
|
||||
rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_ANALOG_BIAS_CTL3,
|
||||
0xa081);
|
||||
/* GE related settings */
|
||||
rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_GE_RELATED_CTL2,
|
||||
0xa009);
|
||||
/* Button A, B, C, D bypass mode */
|
||||
rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_UMP_HID_CTL4,
|
||||
0xcf00);
|
||||
@@ -1475,9 +1478,6 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722)
|
||||
if ((calib_status & 0x0040) == 0x0)
|
||||
break;
|
||||
}
|
||||
/* Release HP-JD, EN_CBJ_TIE_GL/R open, en_osw gating auto done bit */
|
||||
rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_DIGITAL_MISC_CTRL4,
|
||||
0x0010);
|
||||
/* Set ADC09 power entity floating control */
|
||||
rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ADC0A_08_PDE_FLOAT_CTL,
|
||||
0x2a12);
|
||||
@@ -1490,8 +1490,21 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722)
|
||||
/* Set DAC03 and HP power entity floating control */
|
||||
rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_DAC03_HP_PDE_FLOAT_CTL,
|
||||
0x4040);
|
||||
rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_ENT_FLOAT_CTRL_1,
|
||||
0x4141);
|
||||
rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_FLOAT_CTRL_1,
|
||||
0x0101);
|
||||
/* Fine tune PDE40 latency */
|
||||
regmap_write(rt722->regmap, 0x2f58, 0x07);
|
||||
regmap_write(rt722->regmap, 0x2f03, 0x06);
|
||||
/* MIC VRefo */
|
||||
rt722_sdca_index_update_bits(rt722, RT722_VENDOR_REG,
|
||||
RT722_COMBO_JACK_AUTO_CTL1, 0x0200, 0x0200);
|
||||
rt722_sdca_index_update_bits(rt722, RT722_VENDOR_REG,
|
||||
RT722_VREFO_GAT, 0x4000, 0x4000);
|
||||
/* Release HP-JD, EN_CBJ_TIE_GL/R open, en_osw gating auto done bit */
|
||||
rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_DIGITAL_MISC_CTRL4,
|
||||
0x0010);
|
||||
}
|
||||
|
||||
int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
|
||||
@@ -69,6 +69,7 @@ struct rt722_sdca_dmic_kctrl_priv {
|
||||
#define RT722_COMBO_JACK_AUTO_CTL2 0x46
|
||||
#define RT722_COMBO_JACK_AUTO_CTL3 0x47
|
||||
#define RT722_DIGITAL_MISC_CTRL4 0x4a
|
||||
#define RT722_VREFO_GAT 0x63
|
||||
#define RT722_FSM_CTL 0x67
|
||||
#define RT722_SDCA_INTR_REC 0x82
|
||||
#define RT722_SW_CONFIG1 0x8a
|
||||
@@ -127,6 +128,8 @@ struct rt722_sdca_dmic_kctrl_priv {
|
||||
#define RT722_UMP_HID_CTL6 0x66
|
||||
#define RT722_UMP_HID_CTL7 0x67
|
||||
#define RT722_UMP_HID_CTL8 0x68
|
||||
#define RT722_FLOAT_CTRL_1 0x70
|
||||
#define RT722_ENT_FLOAT_CTRL_1 0x76
|
||||
|
||||
/* Parameter & Verb control 01 (0x1a)(NID:20h) */
|
||||
#define RT722_HIDDEN_REG_SW_RESET (0x1 << 14)
|
||||
|
||||
@@ -1155,6 +1155,7 @@ static int wsa881x_probe(struct sdw_slave *pdev,
|
||||
pdev->prop.sink_ports = GENMASK(WSA881X_MAX_SWR_PORTS, 0);
|
||||
pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop;
|
||||
pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
|
||||
pdev->prop.clk_stop_mode1 = true;
|
||||
gpiod_direction_output(wsa881x->sd_n, !wsa881x->sd_n_val);
|
||||
|
||||
wsa881x->regmap = devm_regmap_init_sdw(pdev, &wsa881x_regmap_config);
|
||||
|
||||
@@ -64,7 +64,7 @@ struct avs_icl_memwnd2_desc {
|
||||
struct avs_icl_memwnd2 {
|
||||
union {
|
||||
struct avs_icl_memwnd2_desc slot_desc[AVS_ICL_MEMWND2_SLOTS_COUNT];
|
||||
u8 rsvd[PAGE_SIZE];
|
||||
u8 rsvd[SZ_4K];
|
||||
};
|
||||
u8 slot_array[AVS_ICL_MEMWND2_SLOTS_COUNT][PAGE_SIZE];
|
||||
} __packed;
|
||||
|
||||
@@ -1582,6 +1582,8 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
|
||||
if (!le32_to_cpu(dw->priv.size))
|
||||
return 0;
|
||||
|
||||
w->no_wname_in_kcontrol_name = true;
|
||||
|
||||
if (w->ignore_suspend && !AVS_S0IX_SUPPORTED) {
|
||||
dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n");
|
||||
w->ignore_suspend = false;
|
||||
|
||||
@@ -636,17 +636,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
|
||||
BYT_RT5640_USE_AMCR0F28),
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
|
||||
},
|
||||
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
|
||||
BYT_RT5640_JD_SRC_JD2_IN4N |
|
||||
BYT_RT5640_OVCD_TH_2000UA |
|
||||
BYT_RT5640_OVCD_SF_0P75 |
|
||||
BYT_RT5640_MCLK_EN),
|
||||
},
|
||||
{
|
||||
/* Asus T100TAF, unlike other T100TA* models this one has a mono speaker */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"),
|
||||
@@ -660,6 +650,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
|
||||
BYT_RT5640_SSP0_AIF2 |
|
||||
BYT_RT5640_MCLK_EN),
|
||||
},
|
||||
{
|
||||
/* Asus T100TA and T100TAM, must come after T100TAF (mono spk) match */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
|
||||
},
|
||||
.driver_data = (void *)(BYT_RT5640_IN1_MAP |
|
||||
BYT_RT5640_JD_SRC_JD2_IN4N |
|
||||
BYT_RT5640_OVCD_TH_2000UA |
|
||||
BYT_RT5640_OVCD_SF_0P75 |
|
||||
BYT_RT5640_MCLK_EN),
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
|
||||
@@ -99,6 +99,7 @@ config SND_MESON_AXG_PDM
|
||||
|
||||
config SND_MESON_CARD_UTILS
|
||||
tristate
|
||||
select SND_DYNAMIC_MINORS
|
||||
|
||||
config SND_MESON_CODEC_GLUE
|
||||
tristate
|
||||
|
||||
@@ -318,6 +318,7 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
|
||||
|
||||
dai_link->cpus = cpu;
|
||||
dai_link->num_cpus = 1;
|
||||
dai_link->nonatomic = true;
|
||||
|
||||
ret = meson_card_parse_dai(card, np, dai_link->cpus);
|
||||
if (ret)
|
||||
|
||||
+20
-11
@@ -204,18 +204,26 @@ static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id)
|
||||
unsigned int status;
|
||||
|
||||
regmap_read(fifo->map, FIFO_STATUS1, &status);
|
||||
|
||||
status = FIELD_GET(STATUS1_INT_STS, status);
|
||||
if (status & FIFO_INT_COUNT_REPEAT)
|
||||
snd_pcm_period_elapsed(ss);
|
||||
else
|
||||
dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n",
|
||||
status);
|
||||
|
||||
/* Ack irqs */
|
||||
axg_fifo_ack_irq(fifo, status);
|
||||
|
||||
return IRQ_RETVAL(status);
|
||||
/* Use the thread to call period elapsed on nonatomic links */
|
||||
if (status & FIFO_INT_COUNT_REPEAT)
|
||||
return IRQ_WAKE_THREAD;
|
||||
|
||||
dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n",
|
||||
status);
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static irqreturn_t axg_fifo_pcm_irq_block_thread(int irq, void *dev_id)
|
||||
{
|
||||
struct snd_pcm_substream *ss = dev_id;
|
||||
|
||||
snd_pcm_period_elapsed(ss);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int axg_fifo_pcm_open(struct snd_soc_component *component,
|
||||
@@ -243,8 +251,9 @@ int axg_fifo_pcm_open(struct snd_soc_component *component,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = request_irq(fifo->irq, axg_fifo_pcm_irq_block, 0,
|
||||
dev_name(dev), ss);
|
||||
ret = request_threaded_irq(fifo->irq, axg_fifo_pcm_irq_block,
|
||||
axg_fifo_pcm_irq_block_thread,
|
||||
IRQF_ONESHOT, dev_name(dev), ss);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -392,6 +392,46 @@ void axg_tdm_stream_free(struct axg_tdm_stream *ts)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(axg_tdm_stream_free);
|
||||
|
||||
int axg_tdm_stream_set_cont_clocks(struct axg_tdm_stream *ts,
|
||||
unsigned int fmt)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (fmt & SND_SOC_DAIFMT_CONT) {
|
||||
/* Clock are already enabled - skipping */
|
||||
if (ts->clk_enabled)
|
||||
return 0;
|
||||
|
||||
ret = clk_prepare_enable(ts->iface->mclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(ts->iface->sclk);
|
||||
if (ret)
|
||||
goto err_sclk;
|
||||
|
||||
ret = clk_prepare_enable(ts->iface->lrclk);
|
||||
if (ret)
|
||||
goto err_lrclk;
|
||||
|
||||
ts->clk_enabled = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Clocks are already disabled - skipping */
|
||||
if (!ts->clk_enabled)
|
||||
return 0;
|
||||
|
||||
clk_disable_unprepare(ts->iface->lrclk);
|
||||
err_lrclk:
|
||||
clk_disable_unprepare(ts->iface->sclk);
|
||||
err_sclk:
|
||||
clk_disable_unprepare(ts->iface->mclk);
|
||||
ts->clk_enabled = false;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(axg_tdm_stream_set_cont_clocks);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic AXG TDM formatter driver");
|
||||
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -309,6 +309,7 @@ static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
|
||||
struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
|
||||
int ret;
|
||||
|
||||
switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
@@ -346,7 +347,11 @@ static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream,
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = axg_tdm_stream_set_cont_clocks(ts, iface->fmt);
|
||||
if (ret)
|
||||
dev_err(dai->dev, "failed to apply continuous clock setting\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int axg_tdm_iface_hw_free(struct snd_pcm_substream *substream,
|
||||
@@ -354,19 +359,32 @@ static int axg_tdm_iface_hw_free(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
|
||||
|
||||
/* Stop all attached formatters */
|
||||
axg_tdm_stream_stop(ts);
|
||||
|
||||
return 0;
|
||||
return axg_tdm_stream_set_cont_clocks(ts, 0);
|
||||
}
|
||||
|
||||
static int axg_tdm_iface_prepare(struct snd_pcm_substream *substream,
|
||||
static int axg_tdm_iface_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
|
||||
struct axg_tdm_stream *ts =
|
||||
snd_soc_dai_get_dma_data(dai, substream);
|
||||
|
||||
/* Force all attached formatters to update */
|
||||
return axg_tdm_stream_reset(ts);
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
axg_tdm_stream_start(ts);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
axg_tdm_stream_stop(ts);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axg_tdm_iface_remove_dai(struct snd_soc_dai *dai)
|
||||
@@ -412,8 +430,8 @@ static const struct snd_soc_dai_ops axg_tdm_iface_ops = {
|
||||
.set_fmt = axg_tdm_iface_set_fmt,
|
||||
.startup = axg_tdm_iface_startup,
|
||||
.hw_params = axg_tdm_iface_hw_params,
|
||||
.prepare = axg_tdm_iface_prepare,
|
||||
.hw_free = axg_tdm_iface_hw_free,
|
||||
.trigger = axg_tdm_iface_trigger,
|
||||
};
|
||||
|
||||
/* TDM Backend DAIs */
|
||||
|
||||
@@ -58,12 +58,17 @@ struct axg_tdm_stream {
|
||||
unsigned int physical_width;
|
||||
u32 *mask;
|
||||
bool ready;
|
||||
|
||||
/* For continuous clock tracking */
|
||||
bool clk_enabled;
|
||||
};
|
||||
|
||||
struct axg_tdm_stream *axg_tdm_stream_alloc(struct axg_tdm_iface *iface);
|
||||
void axg_tdm_stream_free(struct axg_tdm_stream *ts);
|
||||
int axg_tdm_stream_start(struct axg_tdm_stream *ts);
|
||||
void axg_tdm_stream_stop(struct axg_tdm_stream *ts);
|
||||
int axg_tdm_stream_set_cont_clocks(struct axg_tdm_stream *ts,
|
||||
unsigned int fmt);
|
||||
|
||||
static inline int axg_tdm_stream_reset(struct axg_tdm_stream *ts)
|
||||
{
|
||||
|
||||
@@ -350,7 +350,9 @@ static int sof_init_environment(struct snd_sof_dev *sdev)
|
||||
}
|
||||
|
||||
ret = sof_select_ipc_and_paths(sdev);
|
||||
if (!ret && plat_data->ipc_type != base_profile->ipc_type) {
|
||||
if (ret) {
|
||||
goto err_machine_check;
|
||||
} else if (plat_data->ipc_type != base_profile->ipc_type) {
|
||||
/* IPC type changed, re-initialize the ops */
|
||||
sof_ops_free(sdev);
|
||||
|
||||
|
||||
@@ -330,14 +330,32 @@ EXPORT_SYMBOL_GPL(snd_sof_dbg_memory_info_init);
|
||||
|
||||
int snd_sof_dbg_init(struct snd_sof_dev *sdev)
|
||||
{
|
||||
struct snd_sof_pdata *plat_data = sdev->pdata;
|
||||
struct snd_sof_dsp_ops *ops = sof_ops(sdev);
|
||||
const struct snd_sof_debugfs_map *map;
|
||||
struct dentry *fw_profile;
|
||||
int i;
|
||||
int err;
|
||||
|
||||
/* use "sof" as top level debugFS dir */
|
||||
sdev->debugfs_root = debugfs_create_dir("sof", NULL);
|
||||
|
||||
/* expose firmware/topology prefix/names for test purposes */
|
||||
fw_profile = debugfs_create_dir("fw_profile", sdev->debugfs_root);
|
||||
|
||||
debugfs_create_str("fw_path", 0444, fw_profile,
|
||||
(char **)&plat_data->fw_filename_prefix);
|
||||
debugfs_create_str("fw_lib_path", 0444, fw_profile,
|
||||
(char **)&plat_data->fw_lib_prefix);
|
||||
debugfs_create_str("tplg_path", 0444, fw_profile,
|
||||
(char **)&plat_data->tplg_filename_prefix);
|
||||
debugfs_create_str("fw_name", 0444, fw_profile,
|
||||
(char **)&plat_data->fw_filename);
|
||||
debugfs_create_str("tplg_name", 0444, fw_profile,
|
||||
(char **)&plat_data->tplg_filename);
|
||||
debugfs_create_u32("ipc_type", 0444, fw_profile,
|
||||
(u32 *)&plat_data->ipc_type);
|
||||
|
||||
/* init dfsentry list */
|
||||
INIT_LIST_HEAD(&sdev->dfsentry_list);
|
||||
|
||||
|
||||
@@ -35,6 +35,9 @@ static const struct sof_dev_desc lnl_desc = {
|
||||
.default_fw_path = {
|
||||
[SOF_IPC_TYPE_4] = "intel/sof-ipc4/lnl",
|
||||
},
|
||||
.default_lib_path = {
|
||||
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/lnl",
|
||||
},
|
||||
.default_tplg_path = {
|
||||
[SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
|
||||
},
|
||||
|
||||
@@ -434,4 +434,5 @@ const struct sof_ipc_pcm_ops ipc3_pcm_ops = {
|
||||
.trigger = sof_ipc3_pcm_trigger,
|
||||
.dai_link_fixup = sof_ipc3_pcm_dai_link_fixup,
|
||||
.reset_hw_params_during_stop = true,
|
||||
.d0i3_supported_in_s0ix = true,
|
||||
};
|
||||
|
||||
+82
-39
@@ -37,6 +37,25 @@ struct sof_ipc4_timestamp_info {
|
||||
snd_pcm_sframes_t delay;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sof_ipc4_pcm_stream_priv - IPC4 specific private data
|
||||
* @time_info: pointer to time info struct if it is supported, otherwise NULL
|
||||
* @chain_dma_allocated: indicates the ChainDMA allocation state
|
||||
*/
|
||||
struct sof_ipc4_pcm_stream_priv {
|
||||
struct sof_ipc4_timestamp_info *time_info;
|
||||
|
||||
bool chain_dma_allocated;
|
||||
};
|
||||
|
||||
static inline struct sof_ipc4_timestamp_info *
|
||||
sof_ipc4_sps_to_time_info(struct snd_sof_pcm_stream *sps)
|
||||
{
|
||||
struct sof_ipc4_pcm_stream_priv *stream_priv = sps->private;
|
||||
|
||||
return stream_priv->time_info;
|
||||
}
|
||||
|
||||
static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state,
|
||||
struct ipc4_pipeline_set_state_data *trigger_list)
|
||||
{
|
||||
@@ -253,14 +272,17 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
|
||||
*/
|
||||
|
||||
static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
|
||||
int direction,
|
||||
struct snd_sof_pcm *spcm, int direction,
|
||||
struct snd_sof_pcm_stream_pipeline_list *pipeline_list,
|
||||
int state, int cmd)
|
||||
{
|
||||
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
|
||||
struct sof_ipc4_pcm_stream_priv *stream_priv;
|
||||
bool allocate, enable, set_fifo_size;
|
||||
struct sof_ipc4_msg msg = {{ 0 }};
|
||||
int i;
|
||||
int ret, i;
|
||||
|
||||
stream_priv = spcm->stream[direction].private;
|
||||
|
||||
switch (state) {
|
||||
case SOF_IPC4_PIPE_RUNNING: /* Allocate and start chained dma */
|
||||
@@ -281,6 +303,11 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
|
||||
set_fifo_size = false;
|
||||
break;
|
||||
case SOF_IPC4_PIPE_RESET: /* Disable and free chained DMA. */
|
||||
|
||||
/* ChainDMA can only be reset if it has been allocated */
|
||||
if (!stream_priv->chain_dma_allocated)
|
||||
return 0;
|
||||
|
||||
allocate = false;
|
||||
enable = false;
|
||||
set_fifo_size = false;
|
||||
@@ -338,7 +365,12 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
|
||||
if (enable)
|
||||
msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK;
|
||||
|
||||
return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
|
||||
ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
|
||||
/* Update the ChainDMA allocation state */
|
||||
if (!ret)
|
||||
stream_priv->chain_dma_allocated = allocate;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
|
||||
@@ -378,7 +410,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
|
||||
* trigger function that handles the rest for the substream.
|
||||
*/
|
||||
if (pipeline->use_chain_dma)
|
||||
return sof_ipc4_chain_dma_trigger(sdev, substream->stream,
|
||||
return sof_ipc4_chain_dma_trigger(sdev, spcm, substream->stream,
|
||||
pipeline_list, state, cmd);
|
||||
|
||||
/* allocate memory for the pipeline data */
|
||||
@@ -452,7 +484,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
|
||||
* Invalidate the stream_start_offset to make sure that it is
|
||||
* going to be updated if the stream resumes
|
||||
*/
|
||||
time_info = spcm->stream[substream->stream].private;
|
||||
time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]);
|
||||
if (time_info)
|
||||
time_info->stream_start_offset = SOF_IPC4_INVALID_STREAM_POSITION;
|
||||
|
||||
@@ -706,12 +738,16 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
|
||||
static void sof_ipc4_pcm_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm)
|
||||
{
|
||||
struct snd_sof_pcm_stream_pipeline_list *pipeline_list;
|
||||
struct sof_ipc4_pcm_stream_priv *stream_priv;
|
||||
int stream;
|
||||
|
||||
for_each_pcm_streams(stream) {
|
||||
pipeline_list = &spcm->stream[stream].pipeline_list;
|
||||
kfree(pipeline_list->pipelines);
|
||||
pipeline_list->pipelines = NULL;
|
||||
|
||||
stream_priv = spcm->stream[stream].private;
|
||||
kfree(stream_priv->time_info);
|
||||
kfree(spcm->stream[stream].private);
|
||||
spcm->stream[stream].private = NULL;
|
||||
}
|
||||
@@ -721,7 +757,8 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm
|
||||
{
|
||||
struct snd_sof_pcm_stream_pipeline_list *pipeline_list;
|
||||
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
|
||||
struct sof_ipc4_timestamp_info *stream_info;
|
||||
struct sof_ipc4_pcm_stream_priv *stream_priv;
|
||||
struct sof_ipc4_timestamp_info *time_info;
|
||||
bool support_info = true;
|
||||
u32 abi_version;
|
||||
u32 abi_offset;
|
||||
@@ -749,33 +786,41 @@ static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!support_info)
|
||||
continue;
|
||||
|
||||
stream_info = kzalloc(sizeof(*stream_info), GFP_KERNEL);
|
||||
if (!stream_info) {
|
||||
stream_priv = kzalloc(sizeof(*stream_priv), GFP_KERNEL);
|
||||
if (!stream_priv) {
|
||||
sof_ipc4_pcm_free(sdev, spcm);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spcm->stream[stream].private = stream_info;
|
||||
spcm->stream[stream].private = stream_priv;
|
||||
|
||||
if (!support_info)
|
||||
continue;
|
||||
|
||||
time_info = kzalloc(sizeof(*time_info), GFP_KERNEL);
|
||||
if (!time_info) {
|
||||
sof_ipc4_pcm_free(sdev, spcm);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
stream_priv->time_info = time_info;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sof_ipc4_build_time_info(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *spcm)
|
||||
static void sof_ipc4_build_time_info(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps)
|
||||
{
|
||||
struct sof_ipc4_copier *host_copier = NULL;
|
||||
struct sof_ipc4_copier *dai_copier = NULL;
|
||||
struct sof_ipc4_llp_reading_slot llp_slot;
|
||||
struct sof_ipc4_timestamp_info *info;
|
||||
struct sof_ipc4_timestamp_info *time_info;
|
||||
struct snd_soc_dapm_widget *widget;
|
||||
struct snd_sof_dai *dai;
|
||||
int i;
|
||||
|
||||
/* find host & dai to locate info in memory window */
|
||||
for_each_dapm_widgets(spcm->list, i, widget) {
|
||||
for_each_dapm_widgets(sps->list, i, widget) {
|
||||
struct snd_sof_widget *swidget = widget->dobj.private;
|
||||
|
||||
if (!swidget)
|
||||
@@ -795,44 +840,44 @@ static void sof_ipc4_build_time_info(struct snd_sof_dev *sdev, struct snd_sof_pc
|
||||
return;
|
||||
}
|
||||
|
||||
info = spcm->private;
|
||||
info->host_copier = host_copier;
|
||||
info->dai_copier = dai_copier;
|
||||
info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_gpdma_reading_slots) +
|
||||
sdev->fw_info_box.offset;
|
||||
time_info = sof_ipc4_sps_to_time_info(sps);
|
||||
time_info->host_copier = host_copier;
|
||||
time_info->dai_copier = dai_copier;
|
||||
time_info->llp_offset = offsetof(struct sof_ipc4_fw_registers,
|
||||
llp_gpdma_reading_slots) + sdev->fw_info_box.offset;
|
||||
|
||||
/* find llp slot used by current dai */
|
||||
for (i = 0; i < SOF_IPC4_MAX_LLP_GPDMA_READING_SLOTS; i++) {
|
||||
sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot));
|
||||
sof_mailbox_read(sdev, time_info->llp_offset, &llp_slot, sizeof(llp_slot));
|
||||
if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id)
|
||||
break;
|
||||
|
||||
info->llp_offset += sizeof(llp_slot);
|
||||
time_info->llp_offset += sizeof(llp_slot);
|
||||
}
|
||||
|
||||
if (i < SOF_IPC4_MAX_LLP_GPDMA_READING_SLOTS)
|
||||
return;
|
||||
|
||||
/* if no llp gpdma slot is used, check aggregated sdw slot */
|
||||
info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_sndw_reading_slots) +
|
||||
sdev->fw_info_box.offset;
|
||||
time_info->llp_offset = offsetof(struct sof_ipc4_fw_registers,
|
||||
llp_sndw_reading_slots) + sdev->fw_info_box.offset;
|
||||
for (i = 0; i < SOF_IPC4_MAX_LLP_SNDW_READING_SLOTS; i++) {
|
||||
sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot));
|
||||
sof_mailbox_read(sdev, time_info->llp_offset, &llp_slot, sizeof(llp_slot));
|
||||
if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id)
|
||||
break;
|
||||
|
||||
info->llp_offset += sizeof(llp_slot);
|
||||
time_info->llp_offset += sizeof(llp_slot);
|
||||
}
|
||||
|
||||
if (i < SOF_IPC4_MAX_LLP_SNDW_READING_SLOTS)
|
||||
return;
|
||||
|
||||
/* check EVAD slot */
|
||||
info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_evad_reading_slot) +
|
||||
sdev->fw_info_box.offset;
|
||||
sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot));
|
||||
time_info->llp_offset = offsetof(struct sof_ipc4_fw_registers,
|
||||
llp_evad_reading_slot) + sdev->fw_info_box.offset;
|
||||
sof_mailbox_read(sdev, time_info->llp_offset, &llp_slot, sizeof(llp_slot));
|
||||
if (llp_slot.node_id != dai_copier->data.gtw_cfg.node_id)
|
||||
info->llp_offset = 0;
|
||||
time_info->llp_offset = 0;
|
||||
}
|
||||
|
||||
static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component,
|
||||
@@ -849,7 +894,7 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component,
|
||||
if (!spcm)
|
||||
return -EINVAL;
|
||||
|
||||
time_info = spcm->stream[substream->stream].private;
|
||||
time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]);
|
||||
/* delay calculation is not supported by current fw_reg ABI */
|
||||
if (!time_info)
|
||||
return 0;
|
||||
@@ -864,7 +909,7 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component,
|
||||
|
||||
static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_sof_pcm_stream *stream,
|
||||
struct snd_sof_pcm_stream *sps,
|
||||
struct sof_ipc4_timestamp_info *time_info)
|
||||
{
|
||||
struct sof_ipc4_copier *host_copier = time_info->host_copier;
|
||||
@@ -918,7 +963,7 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
|
||||
struct sof_ipc4_timestamp_info *time_info;
|
||||
struct sof_ipc4_llp_reading_slot llp;
|
||||
snd_pcm_uframes_t head_cnt, tail_cnt;
|
||||
struct snd_sof_pcm_stream *stream;
|
||||
struct snd_sof_pcm_stream *sps;
|
||||
u64 dai_cnt, host_cnt, host_ptr;
|
||||
struct snd_sof_pcm *spcm;
|
||||
int ret;
|
||||
@@ -927,8 +972,8 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
|
||||
if (!spcm)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
stream = &spcm->stream[substream->stream];
|
||||
time_info = stream->private;
|
||||
sps = &spcm->stream[substream->stream];
|
||||
time_info = sof_ipc4_sps_to_time_info(sps);
|
||||
if (!time_info)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -938,7 +983,7 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
|
||||
* the statistics is complete. And it will not change after the first initiailization.
|
||||
*/
|
||||
if (time_info->stream_start_offset == SOF_IPC4_INVALID_STREAM_POSITION) {
|
||||
ret = sof_ipc4_get_stream_start_offset(sdev, substream, stream, time_info);
|
||||
ret = sof_ipc4_get_stream_start_offset(sdev, substream, sps, time_info);
|
||||
if (ret < 0)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@@ -1030,15 +1075,13 @@ static snd_pcm_sframes_t sof_ipc4_pcm_delay(struct snd_soc_component *component,
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sof_ipc4_timestamp_info *time_info;
|
||||
struct snd_sof_pcm_stream *stream;
|
||||
struct snd_sof_pcm *spcm;
|
||||
|
||||
spcm = snd_sof_find_spcm_dai(component, rtd);
|
||||
if (!spcm)
|
||||
return 0;
|
||||
|
||||
stream = &spcm->stream[substream->stream];
|
||||
time_info = stream->private;
|
||||
time_info = sof_ipc4_sps_to_time_info(&spcm->stream[substream->stream]);
|
||||
/*
|
||||
* Report the stored delay value calculated in the pointer callback.
|
||||
* In the unlikely event that the calculation was skipped/aborted, the
|
||||
|
||||
+6
-7
@@ -325,14 +325,13 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
|
||||
ipc_first = true;
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
if (sdev->system_suspend_target == SOF_SUSPEND_S0IX &&
|
||||
/*
|
||||
* If DSP D0I3 is allowed during S0iX, set the suspend_ignored flag for
|
||||
* D0I3-compatible streams to keep the firmware pipeline running
|
||||
*/
|
||||
if (pcm_ops && pcm_ops->d0i3_supported_in_s0ix &&
|
||||
sdev->system_suspend_target == SOF_SUSPEND_S0IX &&
|
||||
spcm->stream[substream->stream].d0i3_compatible) {
|
||||
/*
|
||||
* trap the event, not sending trigger stop to
|
||||
* prevent the FW pipelines from being stopped,
|
||||
* and mark the flag to ignore the upcoming DAPM
|
||||
* PM events.
|
||||
*/
|
||||
spcm->stream[substream->stream].suspend_ignored = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -116,6 +116,7 @@ struct snd_sof_dai_config_data {
|
||||
* triggers. The FW keeps the host DMA running in this case and
|
||||
* therefore the host must do the same and should stop the DMA during
|
||||
* hw_free.
|
||||
* @d0i3_supported_in_s0ix: Allow DSP D0I3 during S0iX
|
||||
*/
|
||||
struct sof_ipc_pcm_ops {
|
||||
int (*hw_params)(struct snd_soc_component *component, struct snd_pcm_substream *substream,
|
||||
@@ -135,6 +136,7 @@ struct sof_ipc_pcm_ops {
|
||||
bool reset_hw_params_during_stop;
|
||||
bool ipc_first_on_start;
|
||||
bool platform_stop_during_hw_free;
|
||||
bool d0i3_supported_in_s0ix;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
//
|
||||
// tegra186_dspk.c - Tegra186 DSPK driver
|
||||
//
|
||||
// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
@@ -241,14 +240,14 @@ static int tegra186_dspk_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cif_conf.client_bits = TEGRA_ACIF_BITS_24;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
cif_conf.audio_bits = TEGRA_ACIF_BITS_16;
|
||||
cif_conf.client_bits = TEGRA_ACIF_BITS_16;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
cif_conf.audio_bits = TEGRA_ACIF_BITS_32;
|
||||
cif_conf.client_bits = TEGRA_ACIF_BITS_24;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unsupported format!\n");
|
||||
|
||||
@@ -2417,12 +2417,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
|
||||
mcasp_reparent_fck(pdev);
|
||||
|
||||
ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
|
||||
&davinci_mcasp_dai[mcasp->op_mode], 1);
|
||||
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
ret = davinci_mcasp_get_dma_type(mcasp);
|
||||
switch (ret) {
|
||||
case PCM_EDMA:
|
||||
@@ -2449,6 +2443,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = devm_snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
|
||||
&davinci_mcasp_dai[mcasp->op_mode], 1);
|
||||
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
no_audio:
|
||||
ret = davinci_mcasp_init_gpiochip(mcasp);
|
||||
if (ret) {
|
||||
|
||||
@@ -1001,6 +1001,7 @@ static void mock_cxl_endpoint_parse_cdat(struct cxl_port *port)
|
||||
struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
|
||||
struct cxl_dev_state *cxlds = cxlmd->cxlds;
|
||||
struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
|
||||
struct access_coordinate ep_c[ACCESS_COORDINATE_MAX];
|
||||
struct range pmem_range = {
|
||||
.start = cxlds->pmem_res.start,
|
||||
.end = cxlds->pmem_res.end,
|
||||
@@ -1020,6 +1021,12 @@ static void mock_cxl_endpoint_parse_cdat(struct cxl_port *port)
|
||||
dpa_perf_setup(port, &pmem_range, &mds->pmem_perf);
|
||||
|
||||
cxl_memdev_update_perf(cxlmd);
|
||||
|
||||
/*
|
||||
* This function is here to only test the topology iterator. It serves
|
||||
* no other purpose.
|
||||
*/
|
||||
cxl_endpoint_get_perf_coordinates(port, ep_c);
|
||||
}
|
||||
|
||||
static struct cxl_mock_ops cxl_mock_ops = {
|
||||
|
||||
Reference in New Issue
Block a user