"Fossies" - the Fresh Open Source Software Archive

Member "coreboot-6625/src/southbridge/intel/i82801gx/ac97.c" (8 Dec 2010, 7967 Bytes) of package /linux/misc/old/coreboot-6625.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * This file is part of the coreboot project.
    3  *
    4  * Copyright (C) 2008-2009 coresystems GmbH
    5  *
    6  * This program is free software; you can redistribute it and/or
    7  * modify it under the terms of the GNU General Public License as
    8  * published by the Free Software Foundation; version 2 of
    9  * the License.
   10  *
   11  * This program is distributed in the hope that it will be useful,
   12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  * GNU General Public License for more details.
   15  *
   16  * You should have received a copy of the GNU General Public License
   17  * along with this program; if not, write to the Free Software
   18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
   19  */
   20 
   21 #include <console/console.h>
   22 #include <device/device.h>
   23 #include <device/pci.h>
   24 #include <device/pci_ids.h>
   25 #include <arch/io.h>
   26 #include <delay.h>
   27 #include "i82801gx.h"
   28 
   29 #define NAMBAR      0x10
   30 #define   MASTER_VOL    0x02
   31 #define   PAGING    0x24
   32 #define   EXT_AUDIO 0x28
   33 #define   FUNC_SEL  0x66
   34 #define   INFO_IO   0x68
   35 #define   CONNECTOR 0x6a
   36 #define   VENDOR_ID1    0x7c
   37 #define   VENDOR_ID2    0x7e
   38 #define   SEC_VENDOR_ID1 0xfc
   39 #define   SEC_VENDOR_ID2 0xfe
   40 
   41 #define NABMBAR     0x14
   42 #define   GLOB_CNT  0x2c
   43 #define   GLOB_STA  0x30
   44 #define   CAS       0x34
   45 
   46 #define MMBAR       0x10
   47 #define   EXT_MODEM_ID1 0x3c
   48 #define   EXT_MODEM_ID2 0xbc
   49 
   50 #define MBAR        0x14
   51 #define   SEC_CODEC 0x40
   52 
   53 
   54 /* FIXME. This table is probably mainboard specific */
   55 static u16 ac97_function[16*2][4] = {
   56     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   57     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   58     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   59     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   60     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   61     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   62     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   63     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   64     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   65     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   66     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   67     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   68     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   69     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   70     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   71     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   72     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   73     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   74     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   75     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   76     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   77     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   78     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   79     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   80     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   81     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   82     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   83     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   84     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   85     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   86     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) },
   87     { (1 << 5), (2 << 11), (1 << 10), (3 << 13) }
   88 };
   89 
   90 static u16 nabmbar;
   91 static u16 nambar;
   92 
   93 static int ac97_semaphore(void)
   94 {
   95     int timeout;
   96     u8 reg8;
   97 
   98     timeout = 0xffff;
   99     do {
  100         reg8 = inb(nabmbar + CAS);
  101         timeout--;
  102     } while ((reg8 & 1) && timeout);
  103     if (! timeout) {
  104         printk(BIOS_DEBUG, "Timeout!\n");
  105     }
  106 
  107     return (!timeout);
  108 }
  109 
  110 static void init_cnr(void)
  111 {
  112     // TODO
  113 }
  114 
  115 static void program_sigid(struct device *dev, u32 id)
  116 {
  117     pci_write_config32(dev, 0x2c, id);
  118 }
  119 
  120 static void ac97_audio_init(struct device *dev)
  121 {
  122     u16 reg16;
  123     u32 reg32;
  124     int i;
  125 
  126     printk(BIOS_DEBUG, "Initializing AC'97 Audio.\n");
  127 
  128     /* top 16 bits are zero, so don't read them */
  129     nabmbar = pci_read_config16(dev, NABMBAR) & 0xfffe;
  130     nambar = pci_read_config16(dev, NAMBAR) & 0xfffe;
  131 
  132     reg16 = inw(nabmbar + GLOB_CNT);
  133     reg16 |= (1 << 1); /* Remove AC_RESET# */
  134     outw(reg16, nabmbar + GLOB_CNT);
  135 
  136     /* Wait 600ms. Ouch. */
  137     udelay(600 * 1000);
  138 
  139     init_cnr();
  140 
  141     /* Detect Primary AC'97 Codec */
  142     reg32 = inl(nabmbar + GLOB_STA);
  143     if ((reg32 & ((1 << 28) | (1 << 9) | (1 << 8))) == 0) {
  144         /* Primary Codec not found */
  145         printk(BIOS_DEBUG, "No primary codec. Disabling AC'97 Audio.\n");
  146         return;
  147     }
  148 
  149     ac97_semaphore();
  150 
  151     /* Detect if codec is programmable */
  152     outw(0x8000, nambar + MASTER_VOL);
  153     ac97_semaphore();
  154     if (inw(nambar + MASTER_VOL) != 0x8000) {
  155         printk(BIOS_DEBUG, "Codec not programmable. Disabling AC'97 Audio.\n");
  156         return;
  157     }
  158 
  159     /* Program Vendor IDs */
  160     reg32 = inw(nambar + VENDOR_ID1);
  161     reg32 <<= 16;
  162     reg32 |= (u16)inw(nambar + VENDOR_ID2);
  163 
  164     program_sigid(dev, reg32);
  165 
  166     /* Is Codec AC'97 2.3 compliant? */
  167     reg16 = inw(nambar + EXT_AUDIO);
  168     /* [11:10] = 10b -> AC'97 2.3 */
  169     if ((reg16 & 0x0c00) != 0x0800) {
  170         /* No 2.3 Codec. We're done */
  171         return;
  172     }
  173 
  174     /* Select Page 1 */
  175     reg16 = inw(nambar + PAGING);
  176     reg16 &= 0xfff0;
  177     reg16 |= 0x0001;
  178     outw(reg16, nambar + PAGING);
  179 
  180     for (i = 0x0a * 2; i > 0; i--) {
  181         outw(i, nambar + FUNC_SEL);
  182 
  183         /* Function could not be selected. Next one */
  184         if (inw(nambar + FUNC_SEL) != i)
  185             continue;
  186 
  187         reg16 = inw(nambar + INFO_IO);
  188 
  189         /* Function Information present? */
  190         if (!(reg16 & (1 << 0)))
  191             continue;
  192 
  193         /* Function Information valid? */
  194         if (!(reg16 & (1 << 4)))
  195             continue;
  196 
  197         /* Program Buffer Delay [9:5] */
  198         reg16 &= 0x03e0;
  199         reg16 |= ac97_function[i][0];
  200 
  201         /* Program Gain [15:11] */
  202         reg16 |= ac97_function[i][1];
  203 
  204         /* Program Inversion [10] */
  205         reg16 |= ac97_function[i][2];
  206 
  207         outw(reg16, nambar + INFO_IO);
  208 
  209         /* Program Connector / Jack Location */
  210         reg16 = inw(nambar + CONNECTOR);
  211         reg16 &= 0x1fff;
  212         reg16 |= ac97_function[i][3];
  213         outw(reg16, nambar + CONNECTOR);
  214     }
  215 }
  216 
  217 static void ac97_modem_init(struct device *dev)
  218 {
  219     u16 reg16;
  220     u32 reg32;
  221     u16 mmbar, mbar;
  222 
  223     mmbar = pci_read_config16(dev, MMBAR) & 0xfffe;
  224     mbar = pci_read_config16(dev, MBAR) & 0xfffe;
  225 
  226     reg16 = inw(mmbar + EXT_MODEM_ID1);
  227     if ((reg16 & 0xc000) != 0xc000 ) {
  228         if (reg16 & (1 << 0)) {
  229             reg32 = inw(mmbar + VENDOR_ID2);
  230             reg32 <<= 16;
  231             reg32 |= (u16)inw(mmbar + VENDOR_ID1);
  232             program_sigid(dev, reg32);
  233             return;
  234         }
  235     }
  236 
  237     /* Secondary codec? */
  238     reg16 = inw(mbar + SEC_CODEC);
  239     if ((reg16 & (1 << 9)) == 0)
  240         return;
  241 
  242     reg16 = inw(mmbar + EXT_MODEM_ID2);
  243     if ((reg16 & 0xc000) == 0x4000) {
  244         if (reg16 & (1 << 0)) {
  245             reg32 = inw(mmbar + SEC_VENDOR_ID2);
  246             reg32 <<= 16;
  247             reg32 |= (u16)inw(mmbar + SEC_VENDOR_ID1);
  248             program_sigid(dev, reg32);
  249             return;
  250         }
  251     }
  252 }
  253 
  254 static void ac97_set_subsystem(device_t dev, unsigned vendor, unsigned device)
  255 {
  256     if (!vendor || !device) {
  257         pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
  258                 pci_read_config32(dev, PCI_VENDOR_ID));
  259     } else {
  260         pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
  261                 ((device & 0xffff) << 16) | (vendor & 0xffff));
  262     }
  263 }
  264 
  265 static struct pci_operations ac97_pci_ops = {
  266     .set_subsystem    = ac97_set_subsystem,
  267 };
  268 
  269 static struct device_operations ac97_audio_ops = {
  270     .read_resources     = pci_dev_read_resources,
  271     .set_resources      = pci_dev_set_resources,
  272     .enable_resources   = pci_dev_enable_resources,
  273     .init           = ac97_audio_init,
  274     .scan_bus       = 0,
  275     .enable         = i82801gx_enable,
  276     .ops_pci        = &ac97_pci_ops,
  277 };
  278 
  279 static struct device_operations ac97_modem_ops = {
  280     .read_resources     = pci_dev_read_resources,
  281     .set_resources      = pci_dev_set_resources,
  282     .enable_resources   = pci_dev_enable_resources,
  283     .init           = ac97_modem_init,
  284     .scan_bus       = 0,
  285     .enable         = i82801gx_enable,
  286     .ops_pci        = &ac97_pci_ops,
  287 };
  288 
  289 /* 82801GB/GR/GDH/GBM/GHM (ICH7/ICH7R/ICH7DH/ICH7-M/ICH7-M DH) */
  290 /* Note: 82801GU (ICH7-U) doesn't have AC97 audio. */
  291 static const struct pci_driver i82801gx_ac97_audio __pci_driver = {
  292     .ops    = &ac97_audio_ops,
  293     .vendor = PCI_VENDOR_ID_INTEL,
  294     .device = 0x27de,
  295 };
  296 
  297 /* 82801GB/GR/GDH/GBM/GHM (ICH7/ICH7R/ICH7DH/ICH7-M/ICH7-M DH) */
  298 /* Note: 82801GU (ICH7-U) doesn't have AC97 modem. */
  299 static const struct pci_driver i82801gx_ac97_modem __pci_driver = {
  300     .ops    = &ac97_modem_ops,
  301     .vendor = PCI_VENDOR_ID_INTEL,
  302     .device = 0x27dd,
  303 };