1 /*
2  * Copyright (C) 2017 ALLWINNERTECH TECHNOLOGY CO., LTD. All rights reserved.
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions
6  *  are met:
7  *    1. Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *    2. Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the
12  *       distribution.
13  *    3. Neither the name of ALLWINNERTECH TECHNOLOGY CO., LTD. nor the names of
14  *       its contributors may be used to endorse or promote products derived
15  *       from this software without specific prior written permission.
16  *
17  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "string.h" /* for strncmp() */
31 
32 #include "card.h"
33 
34 #include "_core.h"
35 
36 #ifdef CONFIG_USE_MMC_QUIRK
37 
38 #ifndef SDIO_VENDOR_ID_TI
39 #define SDIO_VENDOR_ID_TI       0x0097
40 #endif
41 
42 #ifndef SDIO_DEVICE_ID_TI_WL1271
43 #define SDIO_DEVICE_ID_TI_WL1271    0x4076
44 #endif
45 
46 #ifndef SDIO_VENDOR_ID_XR
47 #define SDIO_VENDOR_ID_XR       0x0020
48 #endif
49 
50 #ifndef SDIO_DEVICE_ID_XRADIO
51 #define SDIO_DEVICE_ID_XRADIO   0x2281
52 #endif
53 
54 static const struct mmc_fixup mmc_fixup_methods[] = {
55     /* by default sdio devices are considered CLK_GATING broken */
56     /* good cards will be whitelisted as they are tested */
57     SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_for_sdio_devices,
58            MMC_QUIRK_BROKEN_CLK_GATING),
59 
60     SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
61            remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
62 
63     SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
64            add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
65 
66     SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
67            add_quirk, MMC_QUIRK_DISABLE_CD),
68 
69     SDIO_FIXUP(SDIO_VENDOR_ID_XR, SDIO_DEVICE_ID_XRADIO,
70            add_quirk, MMC_QUIRK_BROKEN_BYTE_MODE_512),
71 
72     END_FIXUP
73 };
74 
mmc_fixup_device(struct mmc_card * card,const struct mmc_fixup * table)75 void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
76 {
77     const struct mmc_fixup *f;
78     uint64_t rev = cid_rev_card(card);
79 
80     /* Non-core specific workarounds. */
81     if (!table)
82         table = mmc_fixup_methods;
83 
84     for (f = table; f->vendor_fixup; f++) {
85         if ((f->manfid == CID_MANFID_ANY ||
86              f->manfid == card->cid.manfid) &&
87             (f->oemid == CID_OEMID_ANY ||
88              f->oemid == card->cid.oemid) &&
89             (f->name == CID_NAME_ANY ||
90              !strncmp(f->name, card->cid.prod_name,
91                   sizeof(card->cid.prod_name))) &&
92             (f->cis_vendor == card->cis.vendor ||
93              f->cis_vendor == (uint16_t) SDIO_ANY_ID) &&
94             (f->cis_device == card->cis.device ||
95              f->cis_device == (uint16_t) SDIO_ANY_ID) &&
96             rev >= f->rev_start && rev <= f->rev_end) {
97             SD_LOGD("%s calling %pF\n", __func__, f->vendor_fixup);
98             f->vendor_fixup(card, f->data);
99         }
100     }
101 }
102 #endif
103