Merge tag 'topic/i915-hda-componentized-2015-01-12' of git://anongit.freedesktop.org/drm-intel into for-next
Tento commit je obsažen v:
@@ -18,10 +18,12 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/component.h>
|
||||
#include <drm/i915_component.h>
|
||||
#include <sound/core.h>
|
||||
#include <drm/i915_powerwell.h>
|
||||
#include "hda_priv.h"
|
||||
#include "hda_i915.h"
|
||||
#include "hda_intel.h"
|
||||
|
||||
/* Intel HSW/BDW display HDA controller Extended Mode registers.
|
||||
* EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display
|
||||
@@ -31,32 +33,33 @@
|
||||
#define AZX_REG_EM4 0x100c
|
||||
#define AZX_REG_EM5 0x1010
|
||||
|
||||
static int (*get_power)(void);
|
||||
static int (*put_power)(void);
|
||||
static int (*get_cdclk)(void);
|
||||
|
||||
int hda_display_power(bool enable)
|
||||
int hda_display_power(struct hda_intel *hda, bool enable)
|
||||
{
|
||||
if (!get_power || !put_power)
|
||||
struct i915_audio_component *acomp = &hda->audio_component;
|
||||
|
||||
if (!acomp->ops)
|
||||
return -ENODEV;
|
||||
|
||||
pr_debug("HDA display power %s \n",
|
||||
enable ? "Enable" : "Disable");
|
||||
dev_dbg(&hda->chip.pci->dev, "display power %s\n",
|
||||
enable ? "enable" : "disable");
|
||||
if (enable)
|
||||
return get_power();
|
||||
acomp->ops->get_power(acomp->dev);
|
||||
else
|
||||
return put_power();
|
||||
acomp->ops->put_power(acomp->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void haswell_set_bclk(struct azx *chip)
|
||||
void haswell_set_bclk(struct hda_intel *hda)
|
||||
{
|
||||
int cdclk_freq;
|
||||
unsigned int bclk_m, bclk_n;
|
||||
struct i915_audio_component *acomp = &hda->audio_component;
|
||||
|
||||
if (!get_cdclk)
|
||||
if (!acomp->ops)
|
||||
return;
|
||||
|
||||
cdclk_freq = get_cdclk();
|
||||
cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev);
|
||||
switch (cdclk_freq) {
|
||||
case 337500:
|
||||
bclk_m = 16;
|
||||
@@ -80,51 +83,108 @@ void haswell_set_bclk(struct azx *chip)
|
||||
break;
|
||||
}
|
||||
|
||||
azx_writew(chip, EM4, bclk_m);
|
||||
azx_writew(chip, EM5, bclk_n);
|
||||
azx_writew(&hda->chip, EM4, bclk_m);
|
||||
azx_writew(&hda->chip, EM5, bclk_n);
|
||||
}
|
||||
|
||||
|
||||
int hda_i915_init(void)
|
||||
static int hda_component_master_bind(struct device *dev)
|
||||
{
|
||||
int err = 0;
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct azx *chip = card->private_data;
|
||||
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
|
||||
struct i915_audio_component *acomp = &hda->audio_component;
|
||||
int ret;
|
||||
|
||||
get_power = symbol_request(i915_request_power_well);
|
||||
if (!get_power) {
|
||||
pr_warn("hda-i915: get_power symbol get fail\n");
|
||||
return -ENODEV;
|
||||
ret = component_bind_all(dev, acomp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power &&
|
||||
acomp->ops->put_power && acomp->ops->get_cdclk_freq))) {
|
||||
ret = -EINVAL;
|
||||
goto out_unbind;
|
||||
}
|
||||
|
||||
put_power = symbol_request(i915_release_power_well);
|
||||
if (!put_power) {
|
||||
symbol_put(i915_request_power_well);
|
||||
get_power = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
get_cdclk = symbol_request(i915_get_cdclk_freq);
|
||||
if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */
|
||||
pr_warn("hda-i915: get_cdclk symbol get fail\n");
|
||||
|
||||
pr_debug("HDA driver get symbol successfully from i915 module\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int hda_i915_exit(void)
|
||||
{
|
||||
if (get_power) {
|
||||
symbol_put(i915_request_power_well);
|
||||
get_power = NULL;
|
||||
}
|
||||
if (put_power) {
|
||||
symbol_put(i915_release_power_well);
|
||||
put_power = NULL;
|
||||
}
|
||||
if (get_cdclk) {
|
||||
symbol_put(i915_get_cdclk_freq);
|
||||
get_cdclk = NULL;
|
||||
/*
|
||||
* Atm, we don't support dynamic unbinding initiated by the child
|
||||
* component, so pin its containing module until we unbind.
|
||||
*/
|
||||
if (!try_module_get(acomp->ops->owner)) {
|
||||
ret = -ENODEV;
|
||||
goto out_unbind;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_unbind:
|
||||
component_unbind_all(dev, acomp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void hda_component_master_unbind(struct device *dev)
|
||||
{
|
||||
struct snd_card *card = dev_get_drvdata(dev);
|
||||
struct azx *chip = card->private_data;
|
||||
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
|
||||
struct i915_audio_component *acomp = &hda->audio_component;
|
||||
|
||||
module_put(acomp->ops->owner);
|
||||
component_unbind_all(dev, acomp);
|
||||
WARN_ON(acomp->ops || acomp->dev);
|
||||
}
|
||||
|
||||
static const struct component_master_ops hda_component_master_ops = {
|
||||
.bind = hda_component_master_bind,
|
||||
.unbind = hda_component_master_unbind,
|
||||
};
|
||||
|
||||
static int hda_component_master_match(struct device *dev, void *data)
|
||||
{
|
||||
/* i915 is the only supported component */
|
||||
return !strcmp(dev->driver->name, "i915");
|
||||
}
|
||||
|
||||
int hda_i915_init(struct hda_intel *hda)
|
||||
{
|
||||
struct component_match *match = NULL;
|
||||
struct device *dev = &hda->chip.pci->dev;
|
||||
struct i915_audio_component *acomp = &hda->audio_component;
|
||||
int ret;
|
||||
|
||||
component_match_add(dev, &match, hda_component_master_match, hda);
|
||||
ret = component_master_add_with_match(dev, &hda_component_master_ops,
|
||||
match);
|
||||
if (ret < 0)
|
||||
goto out_err;
|
||||
|
||||
/*
|
||||
* Atm, we don't support deferring the component binding, so make sure
|
||||
* i915 is loaded and that the binding successfully completes.
|
||||
*/
|
||||
request_module("i915");
|
||||
|
||||
if (!acomp->ops) {
|
||||
ret = -ENODEV;
|
||||
goto out_master_del;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "bound to i915 component master\n");
|
||||
|
||||
return 0;
|
||||
out_master_del:
|
||||
component_master_del(dev, &hda_component_master_ops);
|
||||
out_err:
|
||||
dev_err(dev, "failed to add i915 component master (%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hda_i915_exit(struct hda_intel *hda)
|
||||
{
|
||||
struct device *dev = &hda->chip.pci->dev;
|
||||
|
||||
component_master_del(dev, &hda_component_master_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __SOUND_HDA_I915_H
|
||||
#define __SOUND_HDA_I915_H
|
||||
|
||||
#ifdef CONFIG_SND_HDA_I915
|
||||
int hda_display_power(bool enable);
|
||||
void haswell_set_bclk(struct azx *chip);
|
||||
int hda_i915_init(void);
|
||||
int hda_i915_exit(void);
|
||||
#else
|
||||
static inline int hda_display_power(bool enable) { return 0; }
|
||||
static inline void haswell_set_bclk(struct azx *chip) { return; }
|
||||
static inline int hda_i915_init(void)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int hda_i915_exit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -63,7 +63,7 @@
|
||||
#include "hda_codec.h"
|
||||
#include "hda_controller.h"
|
||||
#include "hda_priv.h"
|
||||
#include "hda_i915.h"
|
||||
#include "hda_intel.h"
|
||||
|
||||
/* position fix mode */
|
||||
enum {
|
||||
@@ -354,31 +354,6 @@ static char *driver_short_names[] = {
|
||||
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
|
||||
};
|
||||
|
||||
struct hda_intel {
|
||||
struct azx chip;
|
||||
|
||||
/* for pending irqs */
|
||||
struct work_struct irq_pending_work;
|
||||
|
||||
/* sync probing */
|
||||
struct completion probe_wait;
|
||||
struct work_struct probe_work;
|
||||
|
||||
/* card list (for power_save trigger) */
|
||||
struct list_head list;
|
||||
|
||||
/* extra flags */
|
||||
unsigned int irq_pending_warned:1;
|
||||
|
||||
/* VGA-switcheroo setup */
|
||||
unsigned int use_vga_switcheroo:1;
|
||||
unsigned int vga_switcheroo_registered:1;
|
||||
unsigned int init_failed:1; /* delayed init failed */
|
||||
|
||||
/* secondary power domain for hdmi audio under vga device */
|
||||
struct dev_pm_domain hdmi_pm_domain;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
|
||||
{
|
||||
@@ -824,7 +799,7 @@ static int azx_suspend(struct device *dev)
|
||||
if (chip->msi)
|
||||
pci_disable_msi(chip->pci);
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
|
||||
hda_display_power(false);
|
||||
hda_display_power(hda, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -844,8 +819,8 @@ static int azx_resume(struct device *dev)
|
||||
return 0;
|
||||
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
|
||||
hda_display_power(true);
|
||||
haswell_set_bclk(chip);
|
||||
hda_display_power(hda, true);
|
||||
haswell_set_bclk(hda);
|
||||
}
|
||||
if (chip->msi)
|
||||
if (pci_enable_msi(pci) < 0)
|
||||
@@ -888,7 +863,7 @@ static int azx_runtime_suspend(struct device *dev)
|
||||
azx_enter_link_reset(chip);
|
||||
azx_clear_irq_pending(chip);
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
|
||||
hda_display_power(false);
|
||||
hda_display_power(hda, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -914,8 +889,8 @@ static int azx_runtime_resume(struct device *dev)
|
||||
return 0;
|
||||
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
|
||||
hda_display_power(true);
|
||||
haswell_set_bclk(chip);
|
||||
hda_display_power(hda, true);
|
||||
haswell_set_bclk(hda);
|
||||
}
|
||||
|
||||
/* Read STATESTS before controller reset */
|
||||
@@ -1136,8 +1111,8 @@ static int azx_free(struct azx *chip)
|
||||
release_firmware(chip->fw);
|
||||
#endif
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
|
||||
hda_display_power(false);
|
||||
hda_i915_exit();
|
||||
hda_display_power(hda, false);
|
||||
hda_i915_exit(hda);
|
||||
}
|
||||
kfree(hda);
|
||||
|
||||
@@ -1615,8 +1590,12 @@ static int azx_first_init(struct azx *chip)
|
||||
/* initialize chip */
|
||||
azx_init_pci(chip);
|
||||
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
|
||||
haswell_set_bclk(chip);
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
|
||||
struct hda_intel *hda;
|
||||
|
||||
hda = container_of(chip, struct hda_intel, chip);
|
||||
haswell_set_bclk(hda);
|
||||
}
|
||||
|
||||
azx_init_chip(chip, (probe_only[dev] & 2) == 0);
|
||||
|
||||
@@ -1896,13 +1875,10 @@ static int azx_probe_continue(struct azx *chip)
|
||||
/* Request power well for Haswell HDA controller and codec */
|
||||
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
|
||||
#ifdef CONFIG_SND_HDA_I915
|
||||
err = hda_i915_init();
|
||||
if (err < 0) {
|
||||
dev_err(chip->card->dev,
|
||||
"Error request power-well from i915\n");
|
||||
err = hda_i915_init(hda);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
}
|
||||
err = hda_display_power(true);
|
||||
err = hda_display_power(hda, true);
|
||||
if (err < 0) {
|
||||
dev_err(chip->card->dev,
|
||||
"Cannot turn on display power on i915\n");
|
||||
|
71
sound/pci/hda/hda_intel.h
Normální soubor
71
sound/pci/hda/hda_intel.h
Normální soubor
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef __SOUND_HDA_INTEL_H
|
||||
#define __SOUND_HDA_INTEL_H
|
||||
|
||||
#include <drm/i915_component.h>
|
||||
#include "hda_priv.h"
|
||||
|
||||
struct hda_intel {
|
||||
struct azx chip;
|
||||
|
||||
/* for pending irqs */
|
||||
struct work_struct irq_pending_work;
|
||||
|
||||
/* sync probing */
|
||||
struct completion probe_wait;
|
||||
struct work_struct probe_work;
|
||||
|
||||
/* card list (for power_save trigger) */
|
||||
struct list_head list;
|
||||
|
||||
/* extra flags */
|
||||
unsigned int irq_pending_warned:1;
|
||||
|
||||
/* VGA-switcheroo setup */
|
||||
unsigned int use_vga_switcheroo:1;
|
||||
unsigned int vga_switcheroo_registered:1;
|
||||
unsigned int init_failed:1; /* delayed init failed */
|
||||
|
||||
/* secondary power domain for hdmi audio under vga device */
|
||||
struct dev_pm_domain hdmi_pm_domain;
|
||||
|
||||
/* i915 component interface */
|
||||
struct i915_audio_component audio_component;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SND_HDA_I915
|
||||
int hda_display_power(struct hda_intel *hda, bool enable);
|
||||
void haswell_set_bclk(struct hda_intel *hda);
|
||||
int hda_i915_init(struct hda_intel *hda);
|
||||
int hda_i915_exit(struct hda_intel *hda);
|
||||
#else
|
||||
static inline int hda_display_power(struct hda_intel *hda, bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void haswell_set_bclk(struct hda_intel *hda) { return; }
|
||||
static inline int hda_i915_init(struct hda_intel *hda)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int hda_i915_exit(struct hda_intel *hda)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Odkázat v novém úkolu
Zablokovat Uživatele