From owner-freebsd-embedded@FreeBSD.ORG Mon Jul 1 11:06:44 2013 Return-Path: Delivered-To: freebsd-embedded@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id B3CF45EB for ; Mon, 1 Jul 2013 11:06:44 +0000 (UTC) (envelope-from owner-bugmaster@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id A53F310D1 for ; Mon, 1 Jul 2013 11:06:44 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.7/8.14.7) with ESMTP id r61B6iZp085726 for ; Mon, 1 Jul 2013 11:06:44 GMT (envelope-from owner-bugmaster@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.7/8.14.7/Submit) id r61B6iLC085724 for freebsd-embedded@FreeBSD.org; Mon, 1 Jul 2013 11:06:44 GMT (envelope-from owner-bugmaster@FreeBSD.org) Date: Mon, 1 Jul 2013 11:06:44 GMT Message-Id: <201307011106.r61B6iLC085724@freefall.freebsd.org> X-Authentication-Warning: freefall.freebsd.org: gnats set sender to owner-bugmaster@FreeBSD.org using -f From: FreeBSD bugmaster To: freebsd-embedded@FreeBSD.org Subject: Current problem reports assigned to freebsd-embedded@FreeBSD.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2013 11:06:44 -0000 Note: to view an individual PR, use: http://www.freebsd.org/cgi/query-pr.cgi?pr=(number). The following is a listing of current problems submitted by FreeBSD users. These represent problem reports covering all versions including experimental development code and obsolete releases. S Tracker Resp. Description -------------------------------------------------------------------------------- o kern/177878 embedded [rtl8366rb] [patch] Update rtl8366rb switch driver to o bin/177873 embedded [patch] etherswitchcfg(): Change the per port vlangrou o bin/177872 embedded [patch] etherswitchcfg(8) crashes if called with no ar o bin/177871 embedded [patch] etherswitchcfg(8): uninitialized variable whil o kern/172968 embedded [arge] probe/attach occasionally fails to find a PHY o misc/52256 embedded [picobsd] picobsd build script does not read in user/s o kern/42728 embedded [picobsd] many problems in src/usr.sbin/ppp/* after c 7 problems total. From owner-freebsd-embedded@FreeBSD.ORG Mon Jul 1 12:24:56 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id ADE0EAF8 for ; Mon, 1 Jul 2013 12:24:56 +0000 (UTC) (envelope-from zeus@ibs.dn.ua) Received: from relay.ibs.dn.ua (relay.ibs.dn.ua [91.216.196.25]) by mx1.freebsd.org (Postfix) with ESMTP id 1932718C6 for ; Mon, 1 Jul 2013 12:24:55 +0000 (UTC) Received: from ibs.dn.ua (relay.ibs.dn.ua [91.216.196.25]) by relay.ibs.dn.ua with ESMTP id r61CNDMd060984 for ; Mon, 1 Jul 2013 15:23:13 +0300 (EEST) Message-ID: <20130701152313.60982@relay.ibs.dn.ua> Date: Mon, 01 Jul 2013 15:23:13 +0300 From: Zeus Panchenko To: cc: Subject: FreeBSD on ASUS, TP-Link and D-Link routers? Organization: I.B.S. LLC X-Mailer: MH-E 8.3.1; GNU Mailutils 2.99.98; GNU Emacs 24.0.93 X-Face: &sReWXo3Iwtqql1[My(t1Gkx; y?KF@KF`4X+'9Cs@PtK^y%}^.>Mtbpyz6U=,Op:KPOT.uG )Nvx`=er!l?WASh7KeaGhga"1[&yz$_7ir'cVp7o%CGbJ/V)j/=]vzvvcqcZkf; JDurQG6wTg+?/xA go`}1.Ze//K; Fk&/&OoHd'[b7iGt2UO>o(YskCT[_D)kh4!yY'<&:yt+zM=A`@`~9U+P[qS:f; #9z~ Or/Bo#N-'S'!'[3Wog'ADkyMqmGDvga?WW)qd=?)`Y&k=o}>!ST\ X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: Zeus Panchenko List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2013 12:24:56 -0000 hi, may somebody advice, please, how to know, whether FreeBSD embedded can run on ASUS, TP-Link and D-Link routers? for example ASUS WL-500gpv.2 or TP-Link WR741/941 or any other device? what I need is to migrate from OpenWRT to FreeBSD -- Zeus V. Panchenko jid:zeus@im.ibs.dn.ua IT Dpt., I.B.S. LLC GMT+2 (EET) From owner-freebsd-embedded@FreeBSD.ORG Mon Jul 1 16:08:18 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 21C45891 for ; Mon, 1 Jul 2013 16:08:18 +0000 (UTC) (envelope-from adrian.chadd@gmail.com) Received: from mail-wi0-x234.google.com (mail-wi0-x234.google.com [IPv6:2a00:1450:400c:c05::234]) by mx1.freebsd.org (Postfix) with ESMTP id B274A1288 for ; Mon, 1 Jul 2013 16:08:17 +0000 (UTC) Received: by mail-wi0-f180.google.com with SMTP id c10so3246517wiw.13 for ; Mon, 01 Jul 2013 09:08:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:cc:content-type; bh=fB89Oe+wJMwVcwR7bm0V44Is68+Boyb74LefyJ/4fGM=; b=NkYV13m9BjREgC8I7EN1jFKm4RIu//2Cyl124hqvhvrf3RSvPGCRj5vDCYbBWZNLdr uuwxeib6IR14UVeO9kphJFLuHKHgqEdSwbUB0emm1L7uxzLuMYVcSR2ItN6bLvIRgfWK m9ythoJitZkSj6iJBKVLDBNT1InGBBxDusAkUvCscwhnaLJQjC1gWJFNqRdgPohc2oMK Z+qdmlFsk0RweGTt1o2mLo+nM4OLylNscIpEkiSV/mSjuyDIlGDDUzxcaKXJAq45xnnx RGiGHyUlcfIMhf/A08gpFLfH5XT6GtJ3GSpAJbkAVi3W4R6gLEmevDNVR/odSJjHy1Yf DVEw== MIME-Version: 1.0 X-Received: by 10.194.158.130 with SMTP id wu2mr20725756wjb.12.1372694896767; Mon, 01 Jul 2013 09:08:16 -0700 (PDT) Sender: adrian.chadd@gmail.com Received: by 10.216.73.202 with HTTP; Mon, 1 Jul 2013 09:08:16 -0700 (PDT) In-Reply-To: <20130701152313.60982@relay.ibs.dn.ua> References: <20130701152313.60982@relay.ibs.dn.ua> Date: Mon, 1 Jul 2013 09:08:16 -0700 X-Google-Sender-Auth: TXfr0h9wcIUaVgEhFc4cMy_oFVA Message-ID: Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? From: Adrian Chadd To: Zeus Panchenko Content-Type: text/plain; charset=ISO-8859-1 Cc: freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2013 16:08:18 -0000 if it has an ar71xx, ar724x or ar913x SoC, with 32mb of RAM or more, and 8mb flash or more .. yes. -adrian On 1 July 2013 05:23, Zeus Panchenko wrote: > hi, > > may somebody advice, please, how to know, whether FreeBSD embedded can > run on ASUS, TP-Link and D-Link routers? > > for example ASUS WL-500gpv.2 or TP-Link WR741/941 > > or any other device? > > what I need is to migrate from OpenWRT to FreeBSD > > -- > Zeus V. Panchenko jid:zeus@im.ibs.dn.ua > IT Dpt., I.B.S. LLC GMT+2 (EET) > _______________________________________________ > freebsd-embedded@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-embedded > To unsubscribe, send any mail to "freebsd-embedded-unsubscribe@freebsd.org" From owner-freebsd-embedded@FreeBSD.ORG Mon Jul 1 17:51:28 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id BE9703BF for ; Mon, 1 Jul 2013 17:51:28 +0000 (UTC) (envelope-from rafaelhfaria@cenadigital.com.br) Received: from mail-vc0-x234.google.com (mail-vc0-x234.google.com [IPv6:2607:f8b0:400c:c03::234]) by mx1.freebsd.org (Postfix) with ESMTP id 8091D188B for ; Mon, 1 Jul 2013 17:51:28 +0000 (UTC) Received: by mail-vc0-f180.google.com with SMTP id gf11so2180160vcb.11 for ; Mon, 01 Jul 2013 10:51:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cenadigital.com.br; s=mail; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc:content-type; bh=zDUQzyOhM3C33oncET6Kb/TPjnLn8nyzgCZJQ/Gsjf0=; b=ht+TbJxvlGQxDPOzurG8/B/AvxfUqR2WtMhv6HU+MiCi/L5Sn3cBPsAl1EAXWGZtXk Ok/7qs5j+CNDKpTiUbJmOohkrLwP6FNhsLt2Hqo7eVrZIJVBI67G53C97ZGlxi5kv9tv 1BNKVMjv5pX3g9B78uxsGtunS+z2Y6RyY+dgM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc:content-type:x-gm-message-state; bh=zDUQzyOhM3C33oncET6Kb/TPjnLn8nyzgCZJQ/Gsjf0=; b=awhfyL33vBNTv0432MTRfNfXmUsSJb3+XQAB0HCLOUMIq9wsMrj4RStnUhqpeeeKec z/E3oWp2xNLVgMc5oHTcWsGTpfjMaRAeWdMrrDXLQ6ZvMNZ93YVFYSPN3NU5ug011lo/ UjEU4tLg2CMcWeUIJIst3Or7FO68YV5H1p13UuAGu3V79U5orsjJc2GxCEm/zy5bSHs4 7Wn907NjmBS2HzEg6ayZ+fJCboXVhWmtQrpkfR5ISTyZi+r37aW//gor7sE0VravfTsy bWHqFMYul0r/N/1fegjK3TNo+CqgWuerxlbHukMPAnVOrQDWDAtVzbSKGaEyJVaKXEJq PLIQ== X-Received: by 10.220.66.136 with SMTP id n8mr9934917vci.49.1372701088000; Mon, 01 Jul 2013 10:51:28 -0700 (PDT) MIME-Version: 1.0 Received: by 10.58.97.231 with HTTP; Mon, 1 Jul 2013 10:50:47 -0700 (PDT) In-Reply-To: <20130701152313.60982@relay.ibs.dn.ua> References: <20130701152313.60982@relay.ibs.dn.ua> From: Rafael Henrique Faria Date: Mon, 1 Jul 2013 14:50:47 -0300 Message-ID: Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? To: Zeus Panchenko Content-Type: text/plain; charset=ISO-8859-1 X-Gm-Message-State: ALoCoQmzeGHNgz14Ecs56K069tRUNYDdZ6cSZxwGtuWlf11plVHcqGjaZEsuyfzC2LlRR4gVduUy Cc: freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2013 17:51:28 -0000 There is a port from Adrian Chadd to TP-Link WR1043ND: https://wiki.freebsd.org/AdrianChadd/TpLink-Wr1043nd That's a start. On Mon, Jul 1, 2013 at 9:23 AM, Zeus Panchenko wrote: > hi, > > may somebody advice, please, how to know, whether FreeBSD embedded can > run on ASUS, TP-Link and D-Link routers? > > for example ASUS WL-500gpv.2 or TP-Link WR741/941 > > or any other device? > > what I need is to migrate from OpenWRT to FreeBSD > > -- > Zeus V. Panchenko jid:zeus@im.ibs.dn.ua > IT Dpt., I.B.S. LLC GMT+2 (EET) > _______________________________________________ > freebsd-embedded@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-embedded > To unsubscribe, send any mail to "freebsd-embedded-unsubscribe@freebsd.org" -- Rafael Henrique da Silva Faria From owner-freebsd-embedded@FreeBSD.ORG Mon Jul 1 19:03:03 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id C84DCDB6; Mon, 1 Jul 2013 19:03:03 +0000 (UTC) (envelope-from zeus@ibs.dn.ua) Received: from relay.ibs.dn.ua (relay.ibs.dn.ua [91.216.196.25]) by mx1.freebsd.org (Postfix) with ESMTP id 361181C4E; Mon, 1 Jul 2013 19:03:02 +0000 (UTC) Received: from ibs.dn.ua (relay.ibs.dn.ua [91.216.196.25]) by relay.ibs.dn.ua with ESMTP id r61J31gG001638; Mon, 1 Jul 2013 22:03:01 +0300 (EEST) Message-ID: <20130701220301.1636@relay.ibs.dn.ua> Date: Mon, 01 Jul 2013 22:03:01 +0300 From: Zeus Panchenko To: "Adrian Chadd" Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? In-reply-to: Your message of Mon, 1 Jul 2013 09:08:16 -0700 References: <20130701152313.60982@relay.ibs.dn.ua> Organization: I.B.S. LLC X-Mailer: MH-E 8.3.1; GNU Mailutils 2.99.98; GNU Emacs 24.0.93 X-Face: &sReWXo3Iwtqql1[My(t1Gkx; y?KF@KF`4X+'9Cs@PtK^y%}^.>Mtbpyz6U=,Op:KPOT.uG )Nvx`=er!l?WASh7KeaGhga"1[&yz$_7ir'cVp7o%CGbJ/V)j/=]vzvvcqcZkf; JDurQG6wTg+?/xA go`}1.Ze//K; Fk&/&OoHd'[b7iGt2UO>o(YskCT[_D)kh4!yY'<&:yt+zM=A`@`~9U+P[qS:f; #9z~ Or/Bo#N-'S'!'[3Wog'ADkyMqmGDvga?WW)qd=?)`Y&k=o}>!ST\ Cc: freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: Zeus Panchenko List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2013 19:03:03 -0000 Adrian Chadd wrote: > if it has an ar71xx, ar724x or ar913x SoC, with 32mb of RAM or more, > and 8mb flash or more .. yes. thanks much, many of them are ar71xx based -- Zeus V. Panchenko jid:zeus@im.ibs.dn.ua IT Dpt., I.B.S. LLC GMT+2 (EET) From owner-freebsd-embedded@FreeBSD.ORG Mon Jul 1 19:46:09 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id A6B33739 for ; Mon, 1 Jul 2013 19:46:09 +0000 (UTC) (envelope-from adrian.chadd@gmail.com) Received: from mail-qe0-x231.google.com (mail-qe0-x231.google.com [IPv6:2607:f8b0:400d:c02::231]) by mx1.freebsd.org (Postfix) with ESMTP id 6E6B61E00 for ; Mon, 1 Jul 2013 19:46:09 +0000 (UTC) Received: by mail-qe0-f49.google.com with SMTP id cz11so1881665qeb.8 for ; Mon, 01 Jul 2013 12:46:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:cc:content-type; bh=9PELoN9LaPlb1ROqdlWCjb8Tr2r1/utkO9pFbKIkSLI=; b=UkIIFadPAt4ostsJwqsod/KjFaNS01Hf5Gi6FGVaFMV0w0QcDjp4ip0zL325XEJfTQ SlL9UP8rs2PSykKr4Lza+bLBAh9LvX/fknz6c0ew0Jkz6+TAORwVgKSEbhMycVU9Iv2X Bro7CTkMyjCNBrANQBdZqkXzsB7lGPuZgUQdmKNyFh8D+2m65esyQPhZCbxXjrTSE8jK VjXq5AKuyYhMQjXmOGWD8G3iBX4JI5c+P+rIHQIskBKDuYPavRVcWyKtvLpKTdvWpZYc 8wK4yyGxoaMlyt6TL7xCxLfOQTVMN/79e0j0kHAh1HGLsjfcl92/X1U0VP+G2hG/vh/u 9xAQ== MIME-Version: 1.0 X-Received: by 10.224.127.73 with SMTP id f9mr34518430qas.4.1372707969034; Mon, 01 Jul 2013 12:46:09 -0700 (PDT) Sender: adrian.chadd@gmail.com Received: by 10.224.33.198 with HTTP; Mon, 1 Jul 2013 12:46:08 -0700 (PDT) In-Reply-To: <20130701220301.1636@relay.ibs.dn.ua> References: <20130701152313.60982@relay.ibs.dn.ua> <20130701220301.1636@relay.ibs.dn.ua> Date: Mon, 1 Jul 2013 12:46:08 -0700 X-Google-Sender-Auth: 92y-ACVRsmQCrQTGMvqlyEQZclk Message-ID: Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? From: Adrian Chadd To: Zeus Panchenko Content-Type: text/plain; charset=ISO-8859-1 Cc: freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2013 19:46:09 -0000 On 1 July 2013 12:03, Zeus Panchenko wrote: > Adrian Chadd wrote: > >> if it has an ar71xx, ar724x or ar913x SoC, with 32mb of RAM or more, >> and 8mb flash or more .. yes. > > thanks much, many of them are ar71xx based Right. Well, I've done most of the heavy lifting. The build scripts aren't at all polished like openwrt but they're enough for me to run my own test APs at home. So if you'd like to take a crack at bringing up FreebSD on one of the devices, please feel free to grab one, get a serial console going, then ask questions on the -embedded mailing list. I'm happy to help someone implement board support! -adrian From owner-freebsd-embedded@FreeBSD.ORG Mon Jul 1 20:55:02 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 4B0A1EC5; Mon, 1 Jul 2013 20:55:02 +0000 (UTC) (envelope-from lists.br@gmail.com) Received: from mail-wg0-x235.google.com (mail-wg0-x235.google.com [IPv6:2a00:1450:400c:c00::235]) by mx1.freebsd.org (Postfix) with ESMTP id B1984115E; Mon, 1 Jul 2013 20:55:01 +0000 (UTC) Received: by mail-wg0-f53.google.com with SMTP id y10so4179918wgg.20 for ; Mon, 01 Jul 2013 13:55:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=DsMAkcokbqdCnElYAMzTwDfljad/O+S5UZE074v+9Io=; b=oDUaQXBZWQqfwbUo8z0u7ZjVVZmpA3RNxdq5W/+19SsedpJI71IuxYx5nbaLZrOMvs zb5wMzoEsejQ0VZNdWlB1hCC2FyTcct0LDoATTDKJDc3tONmUVAXv3I02z1+38ekd7SU uzWC+lp1ZqN6I1Vk5+6tVNnGdjXlzJ/FnT/1eU7ITmTesLhPVWmJflUfW79a6ro7tr26 guiswoDDVudIZHhK5M9arH+Yv5Pe/rXzkuFVGe4ThH5vSETmoR7sv9dDf/ZRdokYjfrf TjGnq+H99uFK7hIJ7zta2NyzGxcG9A+zY7RoyL2FW4CpaqQyQdI4rz1i99+chaBBcQZg BFOw== MIME-Version: 1.0 X-Received: by 10.180.24.197 with SMTP id w5mr12824750wif.25.1372712100952; Mon, 01 Jul 2013 13:55:00 -0700 (PDT) Received: by 10.216.22.196 with HTTP; Mon, 1 Jul 2013 13:55:00 -0700 (PDT) In-Reply-To: <20130701220301.1636@relay.ibs.dn.ua> References: <20130701152313.60982@relay.ibs.dn.ua> <20130701220301.1636@relay.ibs.dn.ua> Date: Mon, 1 Jul 2013 17:55:00 -0300 Message-ID: Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? From: Luiz Otavio O Souza To: Zeus Panchenko Content-Type: text/plain; charset=ISO-8859-1 X-Content-Filtered-By: Mailman/MimeDel 2.1.14 Cc: freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2013 20:55:02 -0000 On 1 July 2013 16:03, Zeus Panchenko wrote: > Adrian Chadd wrote: > > > if it has an ar71xx, ar724x or ar913x SoC, with 32mb of RAM or more, > > and 8mb flash or more .. yes. > > thanks much, many of them are ar71xx based Devices with 4MB flash and USB are also an option, but in this case you install only the kernel on flash and the root filesystem will use some kind of USB storage (memory stick, usb->[s]ata converters, etc.). I've successfully used TP-Link MR3220 and MR3420 this way. Luiz From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 05:52:17 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 532DB866; Tue, 2 Jul 2013 05:52:17 +0000 (UTC) (envelope-from zeus@ibs.dn.ua) Received: from relay.ibs.dn.ua (relay.ibs.dn.ua [91.216.196.25]) by mx1.freebsd.org (Postfix) with ESMTP id CA1B8178C; Tue, 2 Jul 2013 05:52:16 +0000 (UTC) Received: from ibs.dn.ua (relay.ibs.dn.ua [91.216.196.25]) by relay.ibs.dn.ua with ESMTP id r625qD69052066; Tue, 2 Jul 2013 08:52:13 +0300 (EEST) Message-ID: <20130702085213.52064@relay.ibs.dn.ua> Date: Tue, 02 Jul 2013 08:52:13 +0300 From: Zeus Panchenko To: "Luiz Otavio O Souza" Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? In-reply-to: Your message of Mon, 1 Jul 2013 17:55:00 -0300 References: <20130701152313.60982@relay.ibs.dn.ua> <20130701220301.1636@relay.ibs.dn.ua> Organization: I.B.S. LLC X-Mailer: MH-E 8.3.1; GNU Mailutils 2.99.98; GNU Emacs 24.0.93 X-Face: &sReWXo3Iwtqql1[My(t1Gkx; y?KF@KF`4X+'9Cs@PtK^y%}^.>Mtbpyz6U=,Op:KPOT.uG )Nvx`=er!l?WASh7KeaGhga"1[&yz$_7ir'cVp7o%CGbJ/V)j/=]vzvvcqcZkf; JDurQG6wTg+?/xA go`}1.Ze//K; Fk&/&OoHd'[b7iGt2UO>o(YskCT[_D)kh4!yY'<&:yt+zM=A`@`~9U+P[qS:f; #9z~ Or/Bo#N-'S'!'[3Wog'ADkyMqmGDvga?WW)qd=?)`Y&k=o}>!ST\ Cc: freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: Zeus Panchenko List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 05:52:17 -0000 Luiz Otavio O Souza wrote: > > I've successfully used TP-Link MR3220 and MR3420 this way. > thanks for the point what I in general want from the issue is more or less "common" necessities of small (2-10 workplaces) office and it includes: - vi - pf - PPPoE - hostapd - OpenVPN - bsnmpd - network utilities netstat, ifconfig, route, tcpdump - some optional tools -- mtr -- nrpe -- sendmail -- tmux/screen - anything I missed :) so, what are the chances to build image with these? -- Zeus V. Panchenko jid:zeus@im.ibs.dn.ua IT Dpt., I.B.S. LLC GMT+2 (EET) From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 11:51:12 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id B33E62A7 for ; Tue, 2 Jul 2013 11:51:12 +0000 (UTC) (envelope-from matheus@eternamente.info) Received: from phoenix.eternamente.info (phoenix.eternamente.info [109.169.62.232]) by mx1.freebsd.org (Postfix) with ESMTP id 8CB501830 for ; Tue, 2 Jul 2013 11:51:12 +0000 (UTC) Received: by phoenix.eternamente.info (Postfix, from userid 80) id 443101CC59; Tue, 2 Jul 2013 08:41:27 -0300 (BRT) Received: from 200.164.157.132 (SquirrelMail authenticated user matheus) by arroway.org with HTTP; Tue, 2 Jul 2013 08:41:27 -0300 Message-ID: <18a9b686d7f49d3773ad63eb853b1c88.squirrel@arroway.org> In-Reply-To: <20130702085213.52064@relay.ibs.dn.ua> References: <20130701152313.60982@relay.ibs.dn.ua> <20130701220301.1636@relay.ibs.dn.ua> <20130702085213.52064@relay.ibs.dn.ua> Date: Tue, 2 Jul 2013 08:41:27 -0300 Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? From: "Nenhum_de_Nos" To: freebsd-embedded@freebsd.org User-Agent: SquirrelMail/1.4.21 MIME-Version: 1.0 Content-Type: text/plain;charset=iso-8859-1 Content-Transfer-Encoding: 8bit X-Priority: 3 (Normal) Importance: Normal X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 11:51:12 -0000 On Tue, July 2, 2013 02:52, Zeus Panchenko wrote: > Luiz Otavio O Souza wrote: >> >> I've successfully used TP-Link MR3220 and MR3420 this way. >> > > thanks for the point > > what I in general want from the issue is more or less "common" > necessities of small (2-10 workplaces) office > > and it includes: > > - vi > - pf > - PPPoE > - hostapd > - OpenVPN > - bsnmpd > - network utilities > netstat, ifconfig, route, tcpdump > - some optional tools > -- mtr > -- nrpe > -- sendmail > -- tmux/screen > - anything I missed :) > > so, what are the chances to build image with these? Hi all, I've talked to Luiz some time ago, but I had no time to invest in struggling with the serial interface. As I said before, I have a 1043ND and would really like to see it running FreeBSD. Imagine this hardware running pfSense ? this would be the dlink killer ;) do I need to upload it to the hardware to tinkle with the build script ? First of all I'd like to help this way, as my shell skills are better then my coding skills :) att, matheus -- We will call you Cygnus, The God of balance you shall be A: Because it messes up the order in which people normally read text. Q: Why is top-posting such a bad thing? http://en.wikipedia.org/wiki/Posting_style From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 14:32:19 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 6A8BC3F4; Tue, 2 Jul 2013 14:32:19 +0000 (UTC) (envelope-from lists.br@gmail.com) Received: from mail-wg0-x234.google.com (mail-wg0-x234.google.com [IPv6:2a00:1450:400c:c00::234]) by mx1.freebsd.org (Postfix) with ESMTP id D0FD61102; Tue, 2 Jul 2013 14:32:18 +0000 (UTC) Received: by mail-wg0-f52.google.com with SMTP id b12so4879906wgh.7 for ; Tue, 02 Jul 2013 07:32:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=PNgI2qdvtEy6CPHgY8ruCP+WK0Tbjr09tMHWcI6/tBI=; b=VGPJW+Res/0rWYcqzJy0haG2lVGzlGxp+upoZ2GNn+FwOSJ79LzDlx6MhI1gfXutzX TYYvcM6mqWc9WKGsWu4PHtMfDqYO48v+IvHUVqq411wNJwsYCQOH/vfl8KWe5BNRtoYB 4hrof3p8AyNIzqZ/NLo8n4ZoEXSagJfTQUC/ZyJaejU9RfpXkB96RbVEshhbIuKbck4T G+SmtKlujRvwJueed16h+PbkxG0I/JJHkM2kdXscubutwcXoWGHWnxOHc3bx2QwBmKTD Wg+KPnZqnVVWmoNvv9du1dsaxc5i6pHCthVYfZmUvzDacqKt929f8WCsWAYmn/HeliKf dChw== MIME-Version: 1.0 X-Received: by 10.180.24.197 with SMTP id w5mr15109936wif.25.1372775538021; Tue, 02 Jul 2013 07:32:18 -0700 (PDT) Received: by 10.216.22.196 with HTTP; Tue, 2 Jul 2013 07:32:17 -0700 (PDT) In-Reply-To: <20130702085213.52064@relay.ibs.dn.ua> References: <20130701152313.60982@relay.ibs.dn.ua> <20130701220301.1636@relay.ibs.dn.ua> <20130702085213.52064@relay.ibs.dn.ua> Date: Tue, 2 Jul 2013 11:32:17 -0300 Message-ID: Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? From: Luiz Otavio O Souza To: Zeus Panchenko Content-Type: text/plain; charset=ISO-8859-1 X-Content-Filtered-By: Mailman/MimeDel 2.1.14 Cc: freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 14:32:19 -0000 On 2 July 2013 02:52, Zeus Panchenko wrote: > Luiz Otavio O Souza wrote: > > > > I've successfully used TP-Link MR3220 and MR3420 this way. > > > > thanks for the point > > what I in general want from the issue is more or less "common" > necessities of small (2-10 workplaces) office > > and it includes: > > - vi > - pf > - PPPoE > - hostapd > - OpenVPN > - bsnmpd > - network utilities > netstat, ifconfig, route, tcpdump > - some optional tools > -- mtr > -- nrpe > -- sendmail > -- tmux/screen > - anything I missed :) > > so, what are the chances to build image with these? > > The chances are quite good, it's just a time consuming thing right now. Without proper cross building of ports, you need to build everything in native mode, which could take a while depending on your hardware but other than that it 'just works'. I'm hoping to get crochet working for generating such images (an usb memory stick and a suitable flash kernel image). Luiz From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 14:42:03 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 8399F50B; Tue, 2 Jul 2013 14:42:03 +0000 (UTC) (envelope-from zeus@ibs.dn.ua) Received: from relay.ibs.dn.ua (relay.ibs.dn.ua [91.216.196.25]) by mx1.freebsd.org (Postfix) with ESMTP id 03A391147; Tue, 2 Jul 2013 14:42:02 +0000 (UTC) Received: from ibs.dn.ua (relay.ibs.dn.ua [91.216.196.25]) by relay.ibs.dn.ua with ESMTP id r62EfsaM022473; Tue, 2 Jul 2013 17:41:55 +0300 (EEST) Message-ID: <20130702174154.22471@relay.ibs.dn.ua> Date: Tue, 02 Jul 2013 17:41:54 +0300 From: Zeus Panchenko To: "Luiz Otavio O Souza" Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? In-reply-to: Your message of Tue, 2 Jul 2013 11:32:17 -0300 References: <20130701152313.60982@relay.ibs.dn.ua> <20130701220301.1636@relay.ibs.dn.ua> <20130702085213.52064@relay.ibs.dn.ua> Organization: I.B.S. LLC X-Mailer: MH-E 8.3.1; GNU Mailutils 2.99.98; GNU Emacs 24.0.93 X-Face: &sReWXo3Iwtqql1[My(t1Gkx; y?KF@KF`4X+'9Cs@PtK^y%}^.>Mtbpyz6U=,Op:KPOT.uG )Nvx`=er!l?WASh7KeaGhga"1[&yz$_7ir'cVp7o%CGbJ/V)j/=]vzvvcqcZkf; JDurQG6wTg+?/xA go`}1.Ze//K; Fk&/&OoHd'[b7iGt2UO>o(YskCT[_D)kh4!yY'<&:yt+zM=A`@`~9U+P[qS:f; #9z~ Or/Bo#N-'S'!'[3Wog'ADkyMqmGDvga?WW)qd=?)`Y&k=o}>!ST\ MIME-Version: 1.0 Content-Type: text/plain Content-Transfer-Encoding: quoted-printable Cc: freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: Zeus Panchenko List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 14:42:03 -0000 =2D----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Luiz Otavio O Souza wrote: > - anything I missed :) >=20=20=20=20 > so, what are the chances to build image with these? >=20=20=20=20 >=20 >=20 > The chances are quite good, it's just a time consuming thing right > now. but what are the chances to place all needed at the flash image only? like OpenWRT :) =2D --=20 Zeus V. Panchenko jid:zeus@im.ibs.dn.ua IT Dpt., I.B.S. LLC GMT+2 (EET) =2D----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (FreeBSD) iEYEARECAAYFAlHS5rIACgkQr3jpPg/3oyp7LgCgvva15Eqj//EG0vePhPiYkn1H 67gAoNKvw6NIcSIoqIva/9KHmPlctdKB =3DWUdm =2D----END PGP SIGNATURE----- From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 15:02:20 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 89878D49; Tue, 2 Jul 2013 15:02:20 +0000 (UTC) (envelope-from lists.br@gmail.com) Received: from mail-we0-x232.google.com (mail-we0-x232.google.com [IPv6:2a00:1450:400c:c03::232]) by mx1.freebsd.org (Postfix) with ESMTP id E1C01124E; Tue, 2 Jul 2013 15:02:19 +0000 (UTC) Received: by mail-we0-f178.google.com with SMTP id u53so4460001wes.9 for ; Tue, 02 Jul 2013 08:02:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=zdWUIlUVN2BlNyyMFiUN5QSo4xMG4ufpsWbPo2vKP+M=; b=KT/Dq6tAXVNL0/voZP7YggSv/wIgBRikpA3P+b6GlSLMjF2Bm+c58dmAIBjB+ULc7m LFv8xB/c2sLtv0ISm5cITrYzRdtU2L+KomCRF3JqTLJ+YzQeDMXRMVYaz75plkI3ffEZ IW71M1pDx3DzSftF+XV06OZmyfJTaNInSOq4qDkwoYMEuRQsRtauf7pYGcy0ndBpG8uh tLk7Hsmfg/mKoUas4xwZljvdZGJICGJhPZs8mwSTmdZyIkpqrvE55bjPKt8VPVv8dZtl sxbIp4fTeOesFByO3UuH/8UQMc1vr6+all1VNkzqGqPGjJupt25ghrXOl20T9LhZXCdg EHIA== MIME-Version: 1.0 X-Received: by 10.194.243.226 with SMTP id xb2mr19349733wjc.67.1372777339063; Tue, 02 Jul 2013 08:02:19 -0700 (PDT) Received: by 10.216.22.196 with HTTP; Tue, 2 Jul 2013 08:02:18 -0700 (PDT) In-Reply-To: <20130702174154.22471@relay.ibs.dn.ua> References: <20130701152313.60982@relay.ibs.dn.ua> <20130701220301.1636@relay.ibs.dn.ua> <20130702085213.52064@relay.ibs.dn.ua> <20130702174154.22471@relay.ibs.dn.ua> Date: Tue, 2 Jul 2013 12:02:18 -0300 Message-ID: Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? From: Luiz Otavio O Souza To: Zeus Panchenko Content-Type: text/plain; charset=ISO-8859-1 X-Content-Filtered-By: Mailman/MimeDel 2.1.14 Cc: freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 15:02:20 -0000 On 2 July 2013 11:41, Zeus Panchenko wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Luiz Otavio O Souza wrote: > > - anything I missed :) > > > > so, what are the chances to build image with these? > > > > > > > > The chances are quite good, it's just a time consuming thing right > > now. > > but what are the chances to place all needed at the flash image only? > like OpenWRT :) Sorry, i have no idea... i didn't look at this yet (how small it can be made) and don't have even an idea about how small (or big) would be an image like that. But then, you should look at 8 or 16MB flash routers (and zrouter which generates the smaller images that i'm aware of). Luiz From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 15:08:46 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 0EC8AF7E; Tue, 2 Jul 2013 15:08:46 +0000 (UTC) (envelope-from kibab@olymp.kibab.com) Received: from olymp.kibab.com (olymp.kibab.com [5.9.14.202]) by mx1.freebsd.org (Postfix) with ESMTP id CBB1112E0; Tue, 2 Jul 2013 15:08:44 +0000 (UTC) X-DKIM: OpenDKIM Filter v2.5.2 olymp.kibab.com BF7443F47B DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=bakulin.de; s=default; t=1372777145; bh=cVzM71wchXy0Ff2wBfWPGUrfaZAIKn5hYNchkKYWG0k=; h=Date:From:To:Cc:Subject; b=Xbv3MWK8/PecZoCUqH8c6P41pwp1WZtUjcSSffpglTiWKqn5n3UrTOdr81Hh4RS6f wQ6ctfvRJVHictphUzQH3JE5vFdEO8RZsk2zIYhYavWqEUL+fhylTz51CXkTZUL9tH QXJ27Fa35BwghRIKyToJ1tFLVcGYsCgdnheovM+4= Date: Tue, 2 Jul 2013 16:59:05 +0200 From: Ilya Bakulin To: freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org Subject: [PATCH] SDIO support for Globalscale Dreamplug Message-ID: <20130702145905.GA1847@olymp.kibab.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) Cc: mav@FreeBSD.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 15:08:46 -0000 Hi list, I'm currently developing a SDIO driver for the Globalscale Dreamplug. I have taken SDIO patch for Marvell SoC from [1]. After that I have written some SDIO-related code in sys/dev/mmc/mmc.c, using OpenBSD SDIO code and the patch from Ben Gray ([2]) as a starting point. I have taken Warner's wish to have SDIO code in MMC bus into account, so there is no extra layer of abstraction in my code, SDIO devices will attach directly to MMC bus. This makes possible to implement combo cards support in the future, although I don't support them in my code atm. What is already implemented: * SDIO card detection; * CIS reading, both common CIS and individual functions' CIS; * Function enable. My questions, need answers before I can move further: * Where should I store information retrieved from the CIS? As far as I understand, I should use mmc_ivars structure for that. But in SDIO case the relationship between MMC bus and SDIO card is 1:1, and storing the information about the card in mmc_softc sounds like a good idea -- then I can pass only mmc_softc structure to all functions that need to work with the attached SDIO card. * Should I add any methods to the existing interface files? * Are there any devices on the market that use SDIO interface and which chipsets are supported in FreeBSD? Any Atheros devices? Adrian, what do you think? I have only Dreamplug with Marvell SDIO-based WLAN chip, that doesn't have an opensource driver even for Linux... [1] http://people.freebsd.org/~raj/misc/mv_sdio.c [2] http://lists.freebsd.org/pipermail/freebsd-arm/2012-June/003543.html diff --git a/sys/arm/conf/KIBAB-DPLUG b/sys/arm/conf/KIBAB-DPLUG new file mode 100644 index 0000000..033d398 --- /dev/null +++ b/sys/arm/conf/KIBAB-DPLUG @@ -0,0 +1,171 @@ +# Kernel config for GlobalScale Technologies DreamPlug version 1001. +# +# This is for units that are version 10, revision 01, with NOR SPI flash. +# These units are identified with the number "1001" on the S/N label. +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ +# + +ident KIBAB-DPLUG + +include "../mv/kirkwood/std.db88f6xxx" + +makeoptions FDT_DTS_FILE=dreamplug-1001.dts + +makeoptions MODULES_OVERRIDE="" + +options SOC_MV_KIRKWOOD + +options SCHED_4BSD #4BSD scheduler +options INET #InterNETworking +options INET6 #IPv6 communications protocols +options SOFTUPDATES +options CD9660 #ISO 9660 filesystem +options FFS #Berkeley Fast Filesystem +options MSDOSFS #MS DOS File System (FAT, FAT32) +options NULLFS #NULL filesystem +options TMPFS #Efficient memory filesystem +options SYSVSHM #SYSV-style shared memory +options SYSVMSG #SYSV-style message queues +options SYSVSEM #SYSV-style semaphores +options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions +options GEOM_ELI # Disk encryption. +options GEOM_LABEL # Providers labelization. +options GEOM_PART_GPT # GPT partitioning + +# Flattened Device Tree +device fdt +options FDT +options FDT_DTB_STATIC + +# Misc pseudo devices +device bpf #Required for DHCP +device faith #IPv6-to-IPv4 relaying (translation) +device firmware #firmware(9) required for USB wlan +device gif #IPv6 and IPv4 tunneling +device loop #Network loopback +device md #Memory/malloc disk +device pty #BSD-style compatibility pseudo ttys +device random #Entropy device +device tun #Packet tunnel. +device ether #Required for all ethernet devices +device vlan #802.1Q VLAN support +device wlan #802.11 WLAN support + +# cam support for umass and ahci +device scbus +device pass +device da +device cd + +# Serial ports +device uart + +# Networking +device mge # Marvell Gigabit Ethernet controller +device mii +device e1000phy + +# USB +options USB_HOST_ALIGN=32 # Align DMA to cacheline +#options USB_DEBUG # Compile in USB debug support +device usb # Basic usb support +device ehci # USB host controller +device umass # Mass storage +device uhid # Human-interface devices +device rum # Ralink Technology RT2501USB wireless NICs + +# I2C (TWSI) +device iic +device iicbus + +# SATA +device mvs +device ahci + +# SDIO +device mv_sdio +device mmcsd +device mmc + +# Sound +device sound +device snd_uaudio + +#crypto +device cesa # Marvell security engine +device crypto +device cryptodev + +# IPSec +device enc +options IPSEC +options IPSEC_NAT_T +options TCP_SIGNATURE #include support for RFC 2385 + +#PF +device pf +device pflog +device pfsync + +# ALTQ, required for PF +options ALTQ # Basic ALTQ support +options ALTQ_CBQ # Class Based Queueing +options ALTQ_RED # Random Early Detection +options ALTQ_RIO # RED In/Out +options ALTQ_HFSC # Hierarchical Packet Scheduler +options ALTQ_CDNR # Traffic conditioner +options ALTQ_PRIQ # Priority Queueing +options ALTQ_NOPCC # Required if the TSC is unusable +#options ALTQ_DEBUG + +# Debugging +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols +options BREAK_TO_DEBUGGER +options ALT_BREAK_TO_DEBUGGER +options DDB +options KDB +options DIAGNOSTIC +options INVARIANTS #Enable calls of extra sanity checking +options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS #Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed +#options WITNESS_KDB + +# Enable these options for nfs root configured via BOOTP. +options NFSCL #Network Filesystem Client +options NFSLOCKD #Network Lock Manager +options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options BOOTP +options BOOTP_NFSROOT +#options BOOTP_NFSV3 +options BOOTP_WIRED_TO=mge0 + +# If not using BOOTP, use something like one of these... +#options ROOTDEVNAME=\"ufs:/dev/da1a\" +#options ROOTDEVNAME=\"ufs:/dev/da1s1a\" +#options ROOTDEVNAME=\"ufs:/dev/da1p10\" +#options ROOTDEVNAME=\"nfs:192.168.0.254/dreamplug\" + +# To use this configuration with the (rare) model 1001N (nand flash), +# create a kernel config file that looks like this: +# +# include DREAMPLUG-1001 +# nomakeoptions FDT_DTS_FILE +# makeoptions FDT_DTS_FILE=dreamplug-1001N.dts +# device nand diff --git a/sys/arm/conf/KIBAB-DPLUG-NODBG b/sys/arm/conf/KIBAB-DPLUG-NODBG new file mode 100644 index 0000000..cbced4a --- /dev/null +++ b/sys/arm/conf/KIBAB-DPLUG-NODBG @@ -0,0 +1,43 @@ +# Kernel config for GlobalScale Technologies DreamPlug version 1001. +# +# This is for units that are version 10, revision 01, with NOR SPI flash. +# These units are identified with the number "1001" on the S/N label. +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ +# + +ident KIBAB-DPLUG-NODBG + +include KIBAB-DPLUG + +# Do not compile FDT in kernel +nomakeoptions FDT_DTS_FILE +nooptions FDT_DTB_STATIC + +# Debugging +nomakeoptions DEBUG +nooptions BREAK_TO_DEBUGGER +nooptions ALT_BREAK_TO_DEBUGGER +nooptions DDB +nooptions KDB +nooptions DIAGNOSTIC +nooptions INVARIANTS #Enable calls of extra sanity checking +nooptions INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS #Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed +#options WITNESS_KDB diff --git a/sys/arm/conf/KIBAB-DPLUG-PROD b/sys/arm/conf/KIBAB-DPLUG-PROD new file mode 100644 index 0000000..bae61a4 --- /dev/null +++ b/sys/arm/conf/KIBAB-DPLUG-PROD @@ -0,0 +1,33 @@ +# Kernel config for GlobalScale Technologies DreamPlug version 1001. +# +# This is for units that are version 10, revision 01, with NOR SPI flash. +# These units are identified with the number "1001" on the S/N label. +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ +# + + +include KIBAB-DPLUG-NODBG + +ident KIBAB-DPLUG-PROD + +nooptions NFS_ROOT +nooptions BOOTP +nooptions BOOTP_NFSROOT +nooptions BOOTP_WIRED_TO + diff --git a/sys/arm/mv/files.mv b/sys/arm/mv/files.mv index 116356d..88c0b98 100644 --- a/sys/arm/mv/files.mv +++ b/sys/arm/mv/files.mv @@ -32,6 +32,7 @@ arm/mv/mv_sata.c optional ata | atamvsata arm/mv/mv_ts.c standard arm/mv/timer.c standard arm/mv/twsi.c optional iicbus +arm/mv/mv_sdio.c optional mv_sdio dev/cesa/cesa.c optional cesa dev/mge/if_mge.c optional mge diff --git a/sys/arm/mv/mv_sdio.c b/sys/arm/mv/mv_sdio.c new file mode 100644 index 0000000..73faf08 --- /dev/null +++ b/sys/arm/mv/mv_sdio.c @@ -0,0 +1,1670 @@ +/*- + * Copyright (c) 2009 Semihalf, Rafal Czubak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Driver for Marvell Integrated SDIO Host Controller. + * Works stable in DMA mode. PIO mode has problems with large data transfers + * (timeouts). + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "mmcbr_if.h" + +#include "mv_sdio.h" + +/* Minimum DMA segment size. */ +#define MV_SDIO_DMA_SEGMENT_SIZE 4096 + +/* Transferred block size. */ +#define MV_SDIO_BLOCK_SIZE 512 + +/* Maximum number of blocks the controller can handle. */ +#define MV_SDIO_BLOCKS_MAX 65535 + +/* Halfword bit masks used for command response extraction. */ +#define MV_SDIO_RSP48_BM2 0x0002 /* Lower 2 bits. */ +#define MV_SDIO_RSP48_BM6 0x003f /* Lower 6 bits. */ +#define MV_SDIO_RSP48_BM16 0xffff /* 16 bits */ + +/* SDIO aggregated command interrupts */ +#define MV_SDIO_IRQS_CMD (MV_SDIO_IRQ_CMD | MV_SDIO_IRQ_UNEXPECTED_RSP) +#define MV_SDIO_EIRQS_CMD (MV_SDIO_EIRQ_CMD_TMO | MV_SDIO_EIRQ_CMD_CRC7 | \ + MV_SDIO_EIRQ_CMD_ENDBIT | MV_SDIO_EIRQ_CMD_INDEX | \ + MV_SDIO_EIRQ_CMD_STARTBIT | MV_SDIO_EIRQ_RSP_TBIT) + +/* SDIO aggregated data interrupts */ +#define MV_SDIO_IRQS_DATA (MV_SDIO_IRQ_XFER | MV_SDIO_IRQ_TX_EMPTY | \ + MV_SDIO_IRQ_RX_FULL | MV_SDIO_IRQ_DMA | MV_SDIO_IRQ_AUTOCMD12) +#define MV_SDIO_EIRQS_DATA (MV_SDIO_EIRQ_DATA_TMO | \ + MV_SDIO_EIRQ_DATA_CRC16 | MV_SDIO_EIRQ_DATA_ENDBIT | \ + MV_SDIO_EIRQ_AUTOCMD12 | MV_SDIO_EIRQ_XFER_SIZE | \ + MV_SDIO_EIRQ_CRC_ENDBIT | MV_SDIO_EIRQ_CRC_STARTBIT | \ + MV_SDIO_EIRQ_CRC_STAT) + +/* + * Timing configuration. + */ + +/* SDIO controller base clock frequency. */ +#define MV_SDIO_F_BASE 100000000 /* 200 MHz */ + +/* Maximum SD clock frequency. */ +#define MV_SDIO_F_MAX (MV_SDIO_F_BASE / 2) /* 50 MHz */ + +/* Maximum timeout value. */ +#define MV_SDIO_TMO_MAX 0xf + +/* Reset delay in microseconds. */ +#define MV_SDIO_RESET_DELAY 10000 /* 10 ms */ + +/* Empty FIFO polling delay. */ +#define MV_SDIO_FIFO_EMPTY_DELAY 1000 /* 1 ms */ + +/* Delays between operations on multiple blocks. */ +#define MV_SDIO_RD_DELAY 50 /*50*/ /* Read access time. */ +#define MV_SDIO_WR_DELAY 10 /*10*/ /* Write access time. */ + +/* Maximum clock divider value. */ +#define MV_SDIO_CLK_DIV_MAX 0x7ff + +struct mv_sdio_softc { + device_t sc_dev; + device_t sc_child; + + bus_space_handle_t sc_bsh; + bus_space_tag_t sc_bst; + + int sc_use_dma; + bus_dma_tag_t sc_dmatag; + bus_dmamap_t sc_dmamap; + uint8_t *sc_dmamem; + bus_addr_t sc_physaddr; + int sc_mapped; + size_t sc_dma_size; + + struct resource *sc_mem_res; + int sc_mem_rid; + + struct resource *sc_irq_res; + int sc_irq_rid; + void *sc_ihl; + + struct resource *sc_cd_irq_res; + int sc_cd_irq_rid; + void *sc_cd_ihl; + + uint32_t sc_irq_mask; + uint32_t sc_eirq_mask; + + struct task sc_card_task; + struct callout sc_card_callout; + + struct mtx sc_mtx; + + int sc_bus_busy; + int sc_card_present; + struct mmc_host sc_host; + struct mmc_request *sc_req; + struct mmc_command *sc_curcmd; + + uint32_t sc_data_offset; +}; + +/* Read/write data from/to registers.*/ +static uint32_t MV_SDIO_RD4(struct mv_sdio_softc *, bus_size_t); +static void MV_SDIO_WR4(struct mv_sdio_softc *, bus_size_t, uint32_t); + +static int mv_sdio_probe(device_t); +static int mv_sdio_attach(device_t); + +static int mv_sdio_read_ivar(device_t, device_t, int, uintptr_t *); +static int mv_sdio_write_ivar(device_t, device_t, int, uintptr_t); + +static int mv_sdio_update_ios(device_t, device_t); +static int mv_sdio_request(device_t, device_t, struct mmc_request *); +static int mv_sdio_get_ro(device_t, device_t); +static int mv_sdio_acquire_host(device_t, device_t); +static int mv_sdio_release_host(device_t, device_t); + +/* Finalizes active MMC request. */ +static void mv_sdio_finalize_request(struct mv_sdio_softc *); + +/* Initializes controller's registers. */ +static void mv_sdio_init(device_t); + +/* Initializes host structure. */ +static void mv_sdio_init_host(struct mv_sdio_softc *); + +/* Used to add and handle sysctls. */ +static void mv_sdio_add_sysctls(struct mv_sdio_softc *); +static int mv_sdio_sysctl_use_dma(SYSCTL_HANDLER_ARGS); + +/* DMA initialization and cleanup functions. */ +static int mv_sdio_dma_init(struct mv_sdio_softc *); +static void mv_sdio_dma_finish(struct mv_sdio_softc *); + +/* DMA map load callback. */ +static void mv_sdio_getaddr(void *, bus_dma_segment_t *, int, int); + +/* Prepare command/data before transaction. */ +static int mv_sdio_start_command(struct mv_sdio_softc *, struct + mmc_command *); +static int mv_sdio_start_data(struct mv_sdio_softc *, struct mmc_data *); + +/* Finish command after transaction. */ +static void mv_sdio_finish_command(struct mv_sdio_softc *); + +/* Response handling. */ +static void mv_sdio_handle_136bit_resp(struct mv_sdio_softc *); +static void mv_sdio_handle_48bit_resp(struct mv_sdio_softc *, + struct mmc_command *); + +/* Interrupt handler and interrupt helper functions. */ +static void mv_sdio_intr(void *); +static void mv_sdio_cmd_intr(struct mv_sdio_softc *, uint32_t, uint32_t); +static void mv_sdio_data_intr(struct mv_sdio_softc *, uint32_t, uint32_t); +static void mv_sdio_disable_intr(struct mv_sdio_softc *); + +/* Used after card detect interrupt has been handled. */ +static void mv_sdio_card_task(void *, int); + +/* Read/write data from FIFO in PIO mode. */ +static uint32_t mv_sdio_read_fifo(struct mv_sdio_softc *); +static void mv_sdio_write_fifo(struct mv_sdio_softc *, uint32_t); + +/* + * PIO mode handling. + * + * Inspired by sdhci(4) driver routines. + */ +static void mv_sdio_transfer_pio(struct mv_sdio_softc *); +static void mv_sdio_read_block_pio(struct mv_sdio_softc *); +static void mv_sdio_write_block_pio(struct mv_sdio_softc *); + + +static device_method_t mv_sdio_methods[] = { + /* device_if */ + DEVMETHOD(device_probe, mv_sdio_probe), + DEVMETHOD(device_attach, mv_sdio_attach), + + /* Bus interface */ + DEVMETHOD(bus_read_ivar, mv_sdio_read_ivar), + DEVMETHOD(bus_write_ivar, mv_sdio_write_ivar), + + /* mmcbr_if */ + DEVMETHOD(mmcbr_update_ios, mv_sdio_update_ios), + DEVMETHOD(mmcbr_request, mv_sdio_request), + DEVMETHOD(mmcbr_get_ro, mv_sdio_get_ro), + DEVMETHOD(mmcbr_acquire_host, mv_sdio_acquire_host), + DEVMETHOD(mmcbr_release_host, mv_sdio_release_host), + + {0, 0}, +}; + +static driver_t mv_sdio_driver = { + "sdio", + mv_sdio_methods, + sizeof(struct mv_sdio_softc), +}; +static devclass_t mv_sdio_devclass; + +DRIVER_MODULE( sdio, simplebus, mv_sdio_driver, mv_sdio_devclass, 0, 0); + + +static __inline uint32_t +MV_SDIO_RD4(struct mv_sdio_softc *sc, bus_size_t off) +{ + + return (bus_read_4(sc->sc_mem_res, off)); +} + +static __inline void +MV_SDIO_WR4(struct mv_sdio_softc *sc, bus_size_t off, uint32_t val) +{ + + bus_write_4(sc->sc_mem_res, off, val); +} + +static int platform_sdio_slot_signal( int signal ) +{ + switch( signal ) + { + case MV_SDIO_SIG_CD: + { + return -1; + break; + } + case MV_SDIO_SIG_WP: + return 0; + break; + default: + return -1; + break; + } + + return 0; +} + +static int +mv_sdio_probe(device_t dev) +{ + uint32_t device, revision; + + if (!ofw_bus_is_compatible(dev, "mrvl,sdio")) + return (ENXIO); + + + soc_id(&device, &revision); + + switch (device) { + case MV_DEV_88F6281: + break; + default: + return (ENXIO); + } + + device_set_desc(dev, "Marvell Integrated SDIO Host Controller"); + + return (BUS_PROBE_SPECIFIC); +} + +static int +mv_sdio_attach(device_t dev) +{ + struct mv_sdio_softc *sc; + int task_initialized = 0; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); + + /* Allocate memory and interrupt resources. */ + sc->sc_mem_rid = 0; + sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->sc_mem_rid, RF_ACTIVE); + + if (sc->sc_mem_res == NULL) { + device_printf(dev, "Could not allocate memory!\n"); + goto fail; + } + + sc->sc_irq_rid = 0; + sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->sc_irq_rid, RF_ACTIVE); + + if (sc->sc_irq_res == NULL) { + device_printf(dev, "Could not allocate IRQ!\n"); + goto fail; + } + + sc->sc_bst = rman_get_bustag(sc->sc_mem_res); + sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res); + + + /* Initialize host controller's registers. */ + mv_sdio_init(dev); + + /* Try to setup DMA. */ + sc->sc_mapped = 0; /* No DMA buffer is mapped. */ + sc->sc_use_dma = 1; /* DMA mode is preferred to PIO mode. */ + + if (mv_sdio_dma_init(sc) < 0) { + device_printf(dev, "Falling back to PIO mode.\n"); + sc->sc_use_dma = 0; + } + + /* Add sysctls. */ + mv_sdio_add_sysctls(sc); + + if (platform_sdio_slot_signal(MV_SDIO_SIG_CD) != -1) { + /* Check if card is present in the slot. */ + if (platform_sdio_slot_signal(MV_SDIO_SIG_CD) == 1) + sc->sc_card_present = 1; + } + + TASK_INIT(&sc->sc_card_task, 0, mv_sdio_card_task, sc); + callout_init(&sc->sc_card_callout, 1); + task_initialized = 1; + + /* Setup interrupt. */ + if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | + INTR_MPSAFE, NULL, mv_sdio_intr, sc, &sc->sc_ihl) != 0) { + device_printf(dev, "Could not setup interrupt!\n"); + goto fail; + } + + /* Host can be acquired. */ + sc->sc_bus_busy = 0; + + /* + * Attach MMC bus only if the card is in the slot or card detect is + * not supported on the platform. + */ + if ((platform_sdio_slot_signal(MV_SDIO_SIG_CD) == -1) || + sc->sc_card_present) { + sc->sc_child = device_add_child(dev, "mmc", -1); + + if (sc->sc_child == NULL) { + device_printf(dev, "Could not add MMC bus!\n"); + goto fail; + } + + /* Initialize host structure for MMC bus. */ + mv_sdio_init_host(sc); + + device_set_ivars(sc->sc_child, &sc->sc_host); + } + + return (bus_generic_attach(dev)); + +fail: + mv_sdio_dma_finish(sc); + if (task_initialized) { + callout_drain(&sc->sc_card_callout); + taskqueue_drain(taskqueue_swi, &sc->sc_card_task); + } + if (sc->sc_ihl != NULL) + bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_ihl); + if (sc->sc_cd_ihl != NULL) + bus_teardown_intr(dev, sc->sc_cd_irq_res, sc->sc_cd_ihl); + if (sc->sc_irq_res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, + sc->sc_irq_res); + if (sc->sc_cd_irq_res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, sc->sc_cd_irq_rid, + sc->sc_cd_irq_res); + if (sc->sc_mem_res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, + sc->sc_mem_res); + mtx_destroy(&sc->sc_mtx); + return (ENXIO); +} + +static int +mv_sdio_update_ios(device_t brdev, device_t reqdev) +{ + struct mv_sdio_softc *sc; + struct mmc_host *host; + struct mmc_ios *ios; + uint32_t xfer, clk_div, host_cr; + + sc = device_get_softc(brdev); + host = device_get_ivars(reqdev); + ios = &host->ios; + + mtx_lock(&sc->sc_mtx); + + if (ios->power_mode == power_off) + /* Re-initialize the controller. */ + mv_sdio_init(brdev); + + xfer = MV_SDIO_RD4(sc, MV_SDIO_XFER); + + if (ios->clock == 0) { + /* Disable clock. */ + xfer |= MV_SDIO_XFER_STOP_CLK; + MV_SDIO_WR4(sc, MV_SDIO_XFER, xfer); + + /* Set maximum clock divider. */ + MV_SDIO_WR4(sc, MV_SDIO_CLK_DIV, MV_SDIO_CLK_DIV_MAX); + } else { + /* + * Calculate and set clock divider. + * Clock rate value is: + * clock = MV_SDIO_F_BASE / (clk_div + 1) + * Thus we calculate the divider value as: + * clk_div = (MV_SDIO_F_BASE / clock) - 1 + */ + clk_div = (MV_SDIO_F_BASE / ios->clock) - 1; + if (clk_div > MV_SDIO_CLK_DIV_MAX) + clk_div = MV_SDIO_CLK_DIV_MAX; + MV_SDIO_WR4(sc, MV_SDIO_CLK_DIV, clk_div); + + /* Enable clock. */ + xfer &= ~MV_SDIO_XFER_STOP_CLK; + MV_SDIO_WR4(sc, MV_SDIO_XFER, xfer); + } + + host_cr = MV_SDIO_RD4(sc, MV_SDIO_HOST_CR); + + /* Set card type. */ + if (host->mode == mode_mmc) + host_cr |= MV_SDIO_HOST_CR_MMC; /* MMC card. */ + else + host_cr &= ~MV_SDIO_HOST_CR_MMC; /* SD card. */ + + /* Set bus width. */ + if (ios->bus_width == bus_width_4) + host_cr |= MV_SDIO_HOST_CR_4BIT; /* 4-bit bus width */ + else + host_cr &= ~MV_SDIO_HOST_CR_4BIT; /* 1-bit bus width */ + + /* Set high/normal speed mode. */ +#if 0 /* Some cards have problems with the highspeed-mode + * Not selecting High-Speed mode enables all cards to work + */ + + if ((ios->timing == bus_timing_hs ) && ( 1 == 0 ) ) + host_cr |= MV_SDIO_HOST_CR_HIGHSPEED; + else +#endif + host_cr &= ~MV_SDIO_HOST_CR_HIGHSPEED; + + MV_SDIO_WR4(sc, MV_SDIO_HOST_CR, host_cr); + + mtx_unlock(&sc->sc_mtx); + + return (0); +} + +static int +mv_sdio_request(device_t brdev, device_t reqdev, struct mmc_request *req) +{ + struct mv_sdio_softc *sc; + int rv; + + sc = device_get_softc(brdev); + rv = EBUSY; + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_req != NULL) { + mtx_unlock(&sc->sc_mtx); + return (rv); + } + + sc->sc_req = req; +/* + device_printf(sc->sc_dev, "cmd %d (hw state 0x%04x)\n", + req->cmd->opcode , MV_SDIO_RD4( sc, MV_SDIO_HOST_SR ) ); +*/ + rv = mv_sdio_start_command(sc, req->cmd); + + mtx_unlock(&sc->sc_mtx); + + return (rv); +} + +static int +mv_sdio_get_ro(device_t brdev, device_t reqdev) +{ + int rv; + + /* Check if card is read only. */ + rv = platform_sdio_slot_signal(MV_SDIO_SIG_WP); + + /* + * Assume that card is not write protected, when platform doesn't + * support WP signal. + */ + if (rv < 0) + rv = 0; + + return (rv); +} + +static int +mv_sdio_acquire_host(device_t brdev, device_t reqdev) +{ + struct mv_sdio_softc *sc; + int rv; + + sc = device_get_softc(brdev); + rv = 0; + + mtx_lock(&sc->sc_mtx); + while (sc->sc_bus_busy) + rv = mtx_sleep(sc, &sc->sc_mtx, PZERO, "sdioah", 0); + sc->sc_bus_busy++; + mtx_unlock(&sc->sc_mtx); + + return (rv); +} + +static int +mv_sdio_release_host(device_t brdev, device_t reqdev) +{ + struct mv_sdio_softc *sc; + + sc = device_get_softc(brdev); + + mtx_lock(&sc->sc_mtx); + sc->sc_bus_busy--; + wakeup(sc); + mtx_unlock(&sc->sc_mtx); + + return (0); +} + +static void +mv_sdio_finalize_request(struct mv_sdio_softc *sc) +{ + struct mmc_request *req; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + req = sc->sc_req; + + if (req) { + /* Finalize active request. */ + /*device_printf(sc->sc_dev, "Finalize request %i\n",req->cmd->opcode);*/ + sc->sc_req = NULL; + sc->sc_curcmd = NULL; + req->done(req); + + + } else + device_printf(sc->sc_dev, "No active request to finalize!\n"); +} + +static void +mv_sdio_init(device_t dev) +{ + struct mv_sdio_softc *sc; + uint32_t host_cr; + + sc = device_get_softc(dev); + + /* Disable interrupts. */ + sc->sc_irq_mask = 0; + sc->sc_eirq_mask = 0; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_EN, sc->sc_eirq_mask); + + /* Clear interrupt status registers. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, MV_SDIO_IRQ_ALL); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, MV_SDIO_EIRQ_ALL); + + /* Enable interrupt status registers. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR_EN, MV_SDIO_IRQ_ALL); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR_EN, MV_SDIO_EIRQ_ALL); + + /* Initialize Host Control Register. */ + host_cr = (MV_SDIO_HOST_CR_PUSHPULL | MV_SDIO_HOST_CR_BE | + MV_SDIO_HOST_CR_TMOVAL(MV_SDIO_TMO_MAX) | MV_SDIO_HOST_CR_TMO); + + MV_SDIO_WR4(sc, MV_SDIO_HOST_CR, host_cr); + + /* Stop clock and reset Transfer Mode Register. */ + MV_SDIO_WR4(sc, MV_SDIO_XFER, MV_SDIO_XFER_STOP_CLK); + + /* Set maximum clock divider value. */ + MV_SDIO_WR4(sc, MV_SDIO_CLK_DIV, MV_SDIO_CLK_DIV_MAX); + + /* Reset status, state machine and FIFOs synchronously. */ + MV_SDIO_WR4(sc, MV_SDIO_SW_RESET, MV_SDIO_SW_RESET_ALL); + DELAY(MV_SDIO_RESET_DELAY); +} + +static void +mv_sdio_init_host(struct mv_sdio_softc *sc) +{ + struct mmc_host *host; + + host = &sc->sc_host; + + /* Clear host structure. */ + bzero(host, sizeof(struct mmc_host)); + + /* Calculate minimum and maximum operating frequencies. */ + host->f_min = MV_SDIO_F_BASE / (MV_SDIO_CLK_DIV_MAX + 1); + host->f_max = MV_SDIO_F_MAX; + + /* Set operation conditions (voltage). */ + host->host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340; + + /* Set additional host controller capabilities. */ + host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_HSPEED; +} + +static void +mv_sdio_add_sysctls(struct mv_sdio_softc *sc) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *children; + struct sysctl_oid *tree; + + ctx = device_get_sysctl_ctx(sc->sc_dev); + children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)); + tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "params", + CTLFLAG_RD, 0, "Driver parameters"); + children = SYSCTL_CHILDREN(tree); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "use_dma", + CTLTYPE_UINT | CTLFLAG_RW, sc, 0, mv_sdio_sysctl_use_dma, + "I", "Use DMA for data transfers (0-1)"); +} + +/* + * This sysctl allows switching between DMA and PIO modes for data transfers: + * + * dev.mv_sdio..params.use_dma + * + * Values: + * + * - 1 sets DMA mode + * - 0 sets PIO mode + * + * Driver uses DMA mode by default. + */ +static int +mv_sdio_sysctl_use_dma(SYSCTL_HANDLER_ARGS) +{ + struct mv_sdio_softc *sc; + uint32_t use_dma; + int error; + + sc = (struct mv_sdio_softc *)arg1; + + use_dma = sc->sc_use_dma; + + error = sysctl_handle_int(oidp, &use_dma, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + + if (use_dma > 1) + return (EINVAL); + + mtx_lock(&sc->sc_mtx); + + /* Check if requested mode is already being used. */ + if (sc->sc_use_dma == use_dma) { + mtx_unlock(&sc->sc_mtx); + return (EPERM); + } + + if (!(sc->sc_mapped)) { + device_printf(sc->sc_dev, "DMA not initialized!\n"); + mtx_unlock(&sc->sc_mtx); + return (ENOMEM); + } + + /* Set new mode. */ + sc->sc_use_dma = use_dma; + + mtx_unlock(&sc->sc_mtx); + + return (0); +} + +static void +mv_sdio_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + + if (error != 0) + return; + + /* Get first segment's physical address. */ + *(bus_addr_t *)arg = segs->ds_addr; +} + +static int +mv_sdio_dma_init(struct mv_sdio_softc *sc) +{ + device_t dev; + bus_size_t dmabuf_size; + + dev = sc->sc_dev; + dmabuf_size = MAXPHYS; + + /* Create DMA tag. */ + if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ + MV_SDIO_DMA_SEGMENT_SIZE, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filtfunc, filtfuncarg */ + MAXPHYS, 1, /* maxsize, nsegments */ + MAXPHYS, BUS_DMA_ALLOCNOW, /* maxsegsz, flags */ + NULL, NULL, /* lockfunc, lockfuncarg */ + &sc->sc_dmatag) != 0) { + device_printf(dev, "Could not create DMA tag!\n"); + return (-1); + } + + /* Allocate DMA memory. */ + if (bus_dmamem_alloc(sc->sc_dmatag, (void **)&sc->sc_dmamem, + BUS_DMA_NOWAIT, &sc->sc_dmamap) != 0) { + device_printf(dev, "Could not allocate DMA memory!\n"); + mv_sdio_dma_finish(sc); + return (-1); + } + + /* Find the biggest available DMA buffer size. */ + while (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap, + (void *)sc->sc_dmamem, dmabuf_size, mv_sdio_getaddr, + &sc->sc_physaddr, 0) != 0) { + dmabuf_size >>= 1; + if (dmabuf_size < MV_SDIO_BLOCK_SIZE) { + device_printf(dev, "Could not load DMA map!\n"); + mv_sdio_dma_finish(sc); + return (-1); + } + } + + sc->sc_mapped++; + sc->sc_dma_size = dmabuf_size; + + return (0); +} + +static void +mv_sdio_dma_finish(struct mv_sdio_softc *sc) +{ + + /* Free DMA resources. */ + if (sc->sc_mapped) { + bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap); + sc->sc_mapped--; + } + if (sc->sc_dmamem != NULL) + bus_dmamem_free(sc->sc_dmatag, sc->sc_dmamem, sc->sc_dmamap); + if (sc->sc_dmamap != NULL) + bus_dmamap_destroy(sc->sc_dmatag, sc->sc_dmamap); + if (sc->sc_dmatag != NULL) + bus_dma_tag_destroy(sc->sc_dmatag); +} + +static int +mv_sdio_start_command(struct mv_sdio_softc *sc, struct mmc_command *cmd) +{ + struct mmc_request *req; + uint32_t cmdreg; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + req = sc->sc_req; + + sc->sc_curcmd = cmd; + + cmd->error = MMC_ERR_NONE; + + /* Check if card is in the slot. */ + if ((platform_sdio_slot_signal(MV_SDIO_SIG_CD) != -1) && + (sc->sc_card_present == 0)) { + cmd->error = MMC_ERR_FAILED; + mv_sdio_finalize_request(sc); + return (-1); + } + + /* Check if clock is enabled. */ + if (MV_SDIO_RD4(sc, MV_SDIO_XFER) & MV_SDIO_XFER_STOP_CLK) { + cmd->error = MMC_ERR_FAILED; + mv_sdio_finalize_request(sc); + return (-1); + } + + /* Write command argument. */ + MV_SDIO_WR4(sc, MV_SDIO_CMD_ARGL, cmd->arg & 0xffff); + MV_SDIO_WR4(sc, MV_SDIO_CMD_ARGH, cmd->arg >> 16); + + /* Determine response type. */ + if (cmd->flags & MMC_RSP_136) + cmdreg = MV_SDIO_CMD_RSP_136; + else if (cmd->flags & MMC_RSP_BUSY) + cmdreg = MV_SDIO_CMD_RSP_48_BUSY; + else if (cmd->flags & MMC_RSP_PRESENT) + cmdreg = MV_SDIO_CMD_RSP_48; + else { + /* No response. */ + cmdreg = MV_SDIO_CMD_RSP_NONE; + /* Enable host to detect unexpected response. */ + cmdreg |= MV_SDIO_CMD_UNEXPECTED_RSP; + sc->sc_irq_mask |= MV_SDIO_CMD_UNEXPECTED_RSP; + } + + /* Check command checksum if needed. */ + if (cmd->flags & MMC_RSP_CRC) + cmdreg |= MV_SDIO_CMD_CRC7; + /* Check command opcode if needed. */ + if (cmd->flags & MMC_RSP_OPCODE) + cmdreg |= MV_SDIO_CMD_INDEX_CHECK; + + /* Set commannd opcode. */ + cmdreg |= MV_SDIO_CMD_INDEX(cmd->opcode); + + /* Setup interrupts. */ + sc->sc_irq_mask = MV_SDIO_IRQ_CMD; + sc->sc_eirq_mask = MV_SDIO_EIRQ_ALL; + + /* Prepare data transfer. */ + if (cmd->data) { + cmdreg |= (MV_SDIO_CMD_DATA_PRESENT | MV_SDIO_CMD_DATA_CRC16); + if (mv_sdio_start_data(sc, cmd->data) < 0) { + cmd->error = MMC_ERR_FAILED; + printf("mv_sdio_start_data() failed!\n"); + mv_sdio_finalize_request(sc); + return (-1); + } + } + + /* Write command register. */ + MV_SDIO_WR4(sc, MV_SDIO_CMD, cmdreg); + + /* Clear interrupt status. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, ~MV_SDIO_IRQ_CARD_EVENT /*MV_SDIO_IRQ_ALL*/); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, 0xffff /*MV_SDIO_EIRQ_ALL*/); + + /* Update interrupt/error interrupt enable registers. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_EN, sc->sc_eirq_mask); + + /* Do not complete request, interrupt handler will do this. */ + return (0); +} + +static void +mv_sdio_finish_command(struct mv_sdio_softc *sc) +{ + struct mmc_command *cmd; + struct mmc_data *data; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + cmd = sc->sc_curcmd; + data = cmd->data; + + /* Get response. */ + if (cmd->flags & MMC_RSP_PRESENT) { + if(cmd->flags & MMC_RSP_136) + /* 136-bit response. */ + mv_sdio_handle_136bit_resp(sc); + else + /* 48-bit response. */ + mv_sdio_handle_48bit_resp(sc, NULL); + } + + if (data) { + /* + * Disable command complete interrupt. It has already been + * handled. + */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_CMD; + + /* Enable XFER interrupt. */ + sc->sc_irq_mask |= MV_SDIO_IRQ_XFER; + + /* Check which data interrupts we need to activate. */ + if (sc->sc_use_dma) + /* DMA transaction. */ + sc->sc_irq_mask |= MV_SDIO_IRQ_DMA; + else if (data->flags & MMC_DATA_READ) + /* Read transaction in PIO mode. */ + sc->sc_irq_mask |= MV_SDIO_IRQ_RX_FULL; + else + /* Write transaction in PIO mode. */ + sc->sc_irq_mask |= MV_SDIO_IRQ_TX_EMPTY; + + /* Check if Auto-CMD12 interrupt will be needed. */ + if (sc->sc_req->stop) + sc->sc_irq_mask |= MV_SDIO_IRQ_AUTOCMD12; + + /* Update interrupt enable register. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } else { + /* We're done. Disable interrupts and finalize request. */ + mv_sdio_disable_intr(sc); + mv_sdio_finalize_request(sc); + } +} + +static int +mv_sdio_start_data(struct mv_sdio_softc *sc, struct mmc_data *data) +{ + struct mmc_command *stop; + uint32_t autocmd12reg, xfer, host_sr; + size_t blk_size, blk_count; + int retries; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + /* + * No transfer can be started when FIFO_EMPTY bit in MV_SDIO_HOST_SR + * is not set. This bit is sometimes not set instantly after XFER + * interrupt has been asserted. + */ + host_sr = MV_SDIO_RD4(sc, MV_SDIO_HOST_SR); + + retries = 10; + while (!(host_sr & MV_SDIO_HOST_SR_FIFO_EMPTY)) { + if (retries == 0) + return (-1); + retries--; + DELAY(MV_SDIO_FIFO_EMPTY_DELAY); + host_sr = MV_SDIO_RD4(sc, MV_SDIO_HOST_SR); + } + + /* Clear data offset. */ + sc->sc_data_offset = 0; + + /* + * Set block size. It can be less than or equal to MV_SDIO_BLOCK_SIZE + * bytes. + */ + blk_size = (data->len < MV_SDIO_BLOCK_SIZE) ? data->len : + MV_SDIO_BLOCK_SIZE; + MV_SDIO_WR4(sc, MV_SDIO_BLK_SIZE, blk_size); + + /* Set block count. */ + blk_count = (data->len + MV_SDIO_BLOCK_SIZE - 1) / MV_SDIO_BLOCK_SIZE; + MV_SDIO_WR4(sc, MV_SDIO_BLK_COUNT, blk_count); + + /* We want to initiate transfer by software. */ + xfer = MV_SDIO_XFER_SW_WR_EN; + + if (sc->sc_use_dma) { + /* Synchronize before DMA transfer. */ + if (data->flags & MMC_DATA_READ) + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, + BUS_DMASYNC_PREREAD); + else { + memcpy(sc->sc_dmamem, data->data, data->len); + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, + BUS_DMASYNC_PREWRITE); + } + + /* Write DMA buffer address register. */ + MV_SDIO_WR4(sc, MV_SDIO_DMA_ADDRL, sc->sc_physaddr & 0xffff); + MV_SDIO_WR4(sc, MV_SDIO_DMA_ADDRH, sc->sc_physaddr >> 16); + } else + /* Set PIO transfer mode. */ + xfer |= MV_SDIO_XFER_PIO; + + /* + * Prepare Auto-CMD12. This command is automatically sent to the card + * by the host controller to stop multiple-block data transaction. + */ + if (sc->sc_req->stop) { + stop = sc->sc_req->stop; + + /* Set Auto-CMD12 argument. */ + MV_SDIO_WR4(sc, MV_SDIO_AUTOCMD12_ARGL, stop->arg & 0xffff); + MV_SDIO_WR4(sc, MV_SDIO_AUTOCMD12_ARGH, stop->arg >> 16); + + /* Set Auto-CMD12 opcode. */ + autocmd12reg = MV_SDIO_AUTOCMD12_INDEX(stop->opcode); + + /* Check busy signal if needed. */ + if (stop->flags & MMC_RSP_BUSY) + autocmd12reg |= MV_SDIO_AUTOCMD12_BUSY_CHECK; + /* Check Auto-CMD12 index. */ + if (stop->flags & MMC_RSP_OPCODE) + autocmd12reg |= MV_SDIO_AUTOCMD12_INDEX_CHECK; + + MV_SDIO_WR4(sc, MV_SDIO_AUTOCMD12, autocmd12reg); + + xfer |= MV_SDIO_XFER_AUTOCMD12; + } + + /* Change data direction. */ + if (data->flags & MMC_DATA_READ) + xfer |= MV_SDIO_XFER_TO_HOST; + + /* Write transfer mode register. */ + MV_SDIO_WR4(sc, MV_SDIO_XFER, xfer); + + return (0); +} + +static void +mv_sdio_handle_136bit_resp(struct mv_sdio_softc *sc) +{ + struct mmc_command *cmd; + uint32_t resp[8]; + uint32_t base, extra; + int i, j, off; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + cmd = sc->sc_curcmd; + + /* Collect raw response from the controller. */ + for (i = 0; i < 8; i++) + resp[i] = MV_SDIO_RD4(sc, MV_SDIO_RSP(i)); + + /* Response passed to MMC bus is shifted by one byte. */ + extra = 0; + for (i = 0, j = 7; i < 4; i++, j -= 2) { + off = (i ? 0 : 2); + base = resp[j] | (resp[j - 1] << (16 - off)); + cmd->resp[3 - i] = (base << (6 + off)) + extra; + extra = base >> (26 - off); + } +} + +static void +mv_sdio_handle_48bit_resp(struct mv_sdio_softc *sc, struct mmc_command *stop) +{ + struct mmc_command *cmd; + uint32_t resp[3], word; + uint8_t *rp; + int i; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (stop == NULL) + cmd = sc->sc_curcmd; + else + cmd = stop; + + /* Collect raw response from the controller. */ + for (i = 0; i < 3; i++) { + if (stop == NULL) + resp[i] = MV_SDIO_RD4(sc, MV_SDIO_RSP(i)); + else + resp[i] = MV_SDIO_RD4(sc, MV_SDIO_AUTOCMD12_RSP(i)); + } + + /* Clear MMC bus response buffer. */ + bzero(&cmd->resp[0], 4 * sizeof(uint32_t)); + + /* + * Fill MMC bus response buffer. + */ + + rp = (uint8_t *)&cmd->resp[0]; + + /* Response bits [45:14] */ + word = (resp[1] & MV_SDIO_RSP48_BM16) | + ((resp[0] & MV_SDIO_RSP48_BM16) << 16); + + /* Response bits [15:14] and [13:8] */ + *rp++ = (resp[2] & MV_SDIO_RSP48_BM6) | + ((word & MV_SDIO_RSP48_BM2) << 6); + + /* Response bits [15:14] are already included. */ + word >>= 2; + + /* Response bits [45:16] */ + memcpy(rp, &word, sizeof(uint32_t)); +} + +static void +mv_sdio_intr(void *arg) +{ + struct mv_sdio_softc *sc; + uint32_t irq_stat, eirq_stat; + + sc = (struct mv_sdio_softc *)arg; +#if 0 + device_printf(sc->sc_dev,"intr 0x%04x intr_en 0x%04x hw_state 0x%04x\n", + MV_SDIO_RD4( sc, MV_SDIO_IRQ_SR ) , + MV_SDIO_RD4( sc, MV_SDIO_IRQ_EN ), + MV_SDIO_RD4( sc, MV_SDIO_HOST_SR )); +#endif + + + mtx_lock(&sc->sc_mtx); + + + + irq_stat = MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & sc->sc_irq_mask; + eirq_stat = MV_SDIO_RD4(sc, MV_SDIO_EIRQ_SR) & sc->sc_eirq_mask; + + /* + * In case of error interrupt, interrupt cause will be identified by + * checking bits in error interrupt status register. + */ + irq_stat &= ~MV_SDIO_IRQ_ERR; + + /* Handle command interrupts. */ + if ((irq_stat & MV_SDIO_IRQS_CMD) || + (eirq_stat & MV_SDIO_EIRQS_CMD)) { + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, irq_stat); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, eirq_stat); + mv_sdio_cmd_intr(sc, irq_stat, eirq_stat); + irq_stat &= ~MV_SDIO_IRQS_CMD; + eirq_stat &= ~MV_SDIO_EIRQS_CMD; + } + + /* Handle data interrupts. */ + if ((irq_stat & MV_SDIO_IRQS_DATA) || + (eirq_stat & MV_SDIO_EIRQS_DATA)) { + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, irq_stat); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, eirq_stat); + mv_sdio_data_intr(sc, irq_stat, eirq_stat); + irq_stat &= ~MV_SDIO_IRQS_DATA; + eirq_stat &= ~MV_SDIO_EIRQS_DATA; + } + + /* Handle unexpected interrupts. */ + if (irq_stat) { + device_printf(sc->sc_dev, "Unexpected interrupt(s)! " + "IRQ SR = 0x%08x\n", irq_stat); + /* Clear interrupt status. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, irq_stat); + } + if (eirq_stat) { + device_printf(sc->sc_dev, "Unexpected error interrupt(s)! " + "EIRQ SR = 0x%08x\n", eirq_stat); + /* Clear error interrupt status. */ + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, eirq_stat); + } + + mtx_unlock(&sc->sc_mtx); +} + +static void +mv_sdio_cmd_intr(struct mv_sdio_softc *sc, uint32_t irq, uint32_t eirq) +{ + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (!sc->sc_curcmd) { + device_printf(sc->sc_dev, "Got command interrupt, but there " + "is no active command!\n"); + return; + } + + /* Handle unexpected response error. */ + if (irq & MV_SDIO_IRQ_UNEXPECTED_RSP) { + sc->sc_curcmd->error = MMC_ERR_FAILED; + device_printf(sc->sc_dev, "Unexpected response!\n"); + } + + /* Handle errors. */ + if (eirq & MV_SDIO_EIRQ_CMD_TMO) { + sc->sc_curcmd->error = MMC_ERR_TIMEOUT; + device_printf(sc->sc_dev, "Error - command %d timeout!\n", + sc->sc_curcmd->opcode); + } else if (eirq & MV_SDIO_EIRQ_CMD_CRC7) { + sc->sc_curcmd->error = MMC_ERR_BADCRC; + device_printf(sc->sc_dev, "Error - bad command %d " + "checksum!\n", sc->sc_curcmd->opcode); + } else if (eirq) { + sc->sc_curcmd->error = MMC_ERR_FAILED; + device_printf(sc->sc_dev, "Command %d error!\n", + sc->sc_curcmd->opcode); + } + + if (sc->sc_curcmd->error != MMC_ERR_NONE) { + /* Error. Disable interrupts and finalize request. */ + mv_sdio_disable_intr(sc); + mv_sdio_finalize_request(sc); + return; + } + + if (irq & MV_SDIO_IRQ_CMD) + mv_sdio_finish_command(sc); +} + +static void +mv_sdio_data_intr(struct mv_sdio_softc *sc, uint32_t irq, uint32_t eirq) +{ + struct mmc_command *stop; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (!sc->sc_curcmd) { + device_printf(sc->sc_dev, "Got data interrupt, but there is " + "no active command.\n"); + return; + } + if ((!sc->sc_curcmd->data) && ((sc->sc_curcmd->flags & + MMC_RSP_BUSY) == 0)) { + device_printf(sc->sc_dev, "Got data interrupt, but there is " + "no active data transaction.n\n"); + sc->sc_curcmd->error = MMC_ERR_FAILED; + return; + } + + /* Handle errors. */ + if(eirq & MV_SDIO_EIRQ_DATA_TMO) { + sc->sc_curcmd->error = MMC_ERR_TIMEOUT; + device_printf(sc->sc_dev, "Data %s timeout!\n", + (sc->sc_curcmd->data->flags & MMC_DATA_READ) ? "read" : + "write"); + } else if (eirq & (MV_SDIO_EIRQ_DATA_CRC16 | + MV_SDIO_EIRQ_DATA_ENDBIT)) { + sc->sc_curcmd->error = MMC_ERR_BADCRC; + device_printf(sc->sc_dev, "Bad data checksum!\n"); + } else if (eirq) { + sc->sc_curcmd->error = MMC_ERR_FAILED; + device_printf(sc->sc_dev, "Data error!: 0x%04X \n", + eirq); + + if( 0 != ( eirq & MV_SDIO_EIRQ_CRC_STAT ) ) + { + device_printf(sc->sc_dev, "MV_SDIO_EIRQ_CRC_STAT\n"); + } + } + + /* Handle Auto-CMD12 error. */ + if (eirq & MV_SDIO_EIRQ_AUTOCMD12) { + sc->sc_req->stop->error = MMC_ERR_FAILED; + sc->sc_curcmd->error = MMC_ERR_FAILED; + device_printf(sc->sc_dev, "Auto-CMD12 error!\n"); + } + + if (sc->sc_curcmd->error != MMC_ERR_NONE) { + /* Error. Disable interrupts and finalize request. */ + mv_sdio_disable_intr(sc); + mv_sdio_finalize_request(sc); + return; + } + + /* Handle PIO interrupt. */ + if (irq & (MV_SDIO_IRQ_TX_EMPTY | MV_SDIO_IRQ_RX_FULL)) + mv_sdio_transfer_pio(sc); + + /* Handle DMA interrupt. */ + if (irq & (MV_SDIO_IRQ_DMA)) { + /* Synchronize DMA buffer. */ + if (MV_SDIO_RD4(sc, MV_SDIO_XFER) & MV_SDIO_XFER_TO_HOST) { + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, + BUS_DMASYNC_POSTWRITE); + memcpy(sc->sc_curcmd->data->data, sc->sc_dmamem, + sc->sc_curcmd->data->len); + } else + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, + BUS_DMASYNC_POSTREAD); + + /* Disable DMA interrupt. */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_DMA; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } + + /* Handle Auto-CMD12 interrupt. */ + if (irq & (MV_SDIO_IRQ_AUTOCMD12)) { + stop = sc->sc_req->stop; + /* Get 48-bit response. */ + mv_sdio_handle_48bit_resp(sc, stop); + + /* Disable Auto-CMD12 interrupt. */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_AUTOCMD12; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } + + /* Transfer finished. Disable interrupts and finalize request. */ + if (irq & (MV_SDIO_IRQ_XFER)) { + mv_sdio_disable_intr(sc); + mv_sdio_finalize_request(sc); + } +} + +static void +mv_sdio_disable_intr(struct mv_sdio_softc *sc) +{ + + /* Disable interrupts that were enabled. */ + sc->sc_irq_mask &= ~(sc->sc_irq_mask); + sc->sc_eirq_mask &= ~(sc->sc_eirq_mask); + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_EN, sc->sc_eirq_mask); +} + +static void +mv_sdio_card_task(void *arg, int pending) +{ + struct mv_sdio_softc *sc; + + int device_probe_and_attach_ret_val = 0; + + sc = (struct mv_sdio_softc *)arg; + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_card_present) { + if (sc->sc_child) { + mtx_unlock(&sc->sc_mtx); + return; + } + + /* Initialize host controller's registers. */ + mv_sdio_init(sc->sc_dev); + + sc->sc_child = device_add_child(sc->sc_dev, "mmc", -1); + if (sc->sc_child == NULL) { + device_printf(sc->sc_dev, "Could not add MMC bus!\n"); + mtx_unlock(&sc->sc_mtx); + return; + } + + /* Initialize host structure for MMC bus. */ + mv_sdio_init_host(sc); + + device_set_ivars(sc->sc_child, &sc->sc_host); + + mtx_unlock(&sc->sc_mtx); + + device_probe_and_attach_ret_val = device_probe_and_attach(sc->sc_child); + + if( 0 != device_probe_and_attach_ret_val ) { + device_printf(sc->sc_dev, "MMC bus failed on probe " + "and attach! %i\n",device_probe_and_attach_ret_val); + device_delete_child(sc->sc_dev, sc->sc_child); + sc->sc_child = NULL; + } + } else { + if (sc->sc_child == NULL) { + mtx_unlock(&sc->sc_mtx); + return; + } + + mtx_unlock(&sc->sc_mtx); + if (device_delete_child(sc->sc_dev, sc->sc_child) != 0) { + device_printf(sc->sc_dev, "Could not delete MMC " + "bus!\n"); + } + sc->sc_child = NULL; + } +} + +static uint32_t +mv_sdio_read_fifo(struct mv_sdio_softc *sc) +{ + uint32_t data; + device_printf(sc->sc_dev, "This is not tested, yet MV_SDIO_FIFO not ensured\n "); + + while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_RX_FULL)); + data = MV_SDIO_RD4(sc, MV_SDIO_FIFO); + while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_RX_FULL)); + data |= (MV_SDIO_RD4(sc, MV_SDIO_FIFO) << 16); + return data; +} + +static void +mv_sdio_write_fifo(struct mv_sdio_softc *sc, uint32_t val) +{ + while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_TX_EMPTY)); + MV_SDIO_WR4(sc, MV_SDIO_FIFO, val & 0xffff); + while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_TX_EMPTY)); + MV_SDIO_WR4(sc, MV_SDIO_FIFO, val >> 16); +} + +static void +mv_sdio_transfer_pio(struct mv_sdio_softc *sc) +{ + struct mmc_command *cmd; + + cmd = sc->sc_curcmd; + + if (cmd->data->flags & MMC_DATA_READ) { + while (MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & + MV_SDIO_IRQ_RX_FULL) { + mv_sdio_read_block_pio(sc); + /* + * Assert delay after each block transfer to meet read + * access timing constraint. + */ + DELAY(MV_SDIO_RD_DELAY); + if (sc->sc_data_offset >= cmd->data->len) + break; + } + /* All blocks read in PIO mode. Disable interrupt. */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_RX_FULL; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } else { + while (MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & + MV_SDIO_IRQ_TX_EMPTY) { + mv_sdio_write_block_pio(sc); + /* Wait while card is programming the memory. */ + while ((MV_SDIO_RD4(sc, MV_SDIO_HOST_SR) & + MV_SDIO_HOST_SR_CARD_BUSY)); + /* + * Assert delay after each block transfer to meet + * write access timing constraint. + */ + DELAY(MV_SDIO_WR_DELAY); + + if (sc->sc_data_offset >= cmd->data->len) + break; + } + /* All blocks written in PIO mode. Disable interrupt. */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_TX_EMPTY; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } +} + +static void +mv_sdio_read_block_pio(struct mv_sdio_softc *sc) +{ + uint32_t data; + char *buffer; + size_t left; + + buffer = sc->sc_curcmd->data->data; + buffer += sc->sc_data_offset; + /* Transfer one block at a time. */ + left = min(MV_SDIO_BLOCK_SIZE, sc->sc_curcmd->data->len - + sc->sc_data_offset); + sc->sc_data_offset += left; + + /* Handle unaligned and aligned buffer cases. */ + if ((intptr_t)buffer & 3) { + while (left > 3) { + data = mv_sdio_read_fifo(sc); + buffer[0] = data; + buffer[1] = (data >> 8); + buffer[2] = (data >> 16); + buffer[3] = (data >> 24); + buffer += 4; + left -= 4; + } + } else { + while (left > 3) { + data = mv_sdio_read_fifo(sc); + *((uint32_t *)buffer) = data; + buffer += 4; + left -= 4; + } + } + /* Handle uneven size case. */ + if (left > 0) { + data = mv_sdio_read_fifo(sc); + while (left > 0) { + *(buffer++) = data; + data >>= 8; + left--; + } + } +} + +static void +mv_sdio_write_block_pio(struct mv_sdio_softc *sc) +{ + uint32_t data = 0; + char *buffer; + size_t left; + + buffer = sc->sc_curcmd->data->data; + buffer += sc->sc_data_offset; + /* Transfer one block at a time. */ + left = min(MV_SDIO_BLOCK_SIZE, sc->sc_curcmd->data->len - + sc->sc_data_offset); + sc->sc_data_offset += left; + + /* Handle unaligned and aligned buffer cases. */ + if ((intptr_t)buffer & 3) { + while (left > 3) { + data = buffer[0] + + (buffer[1] << 8) + + (buffer[2] << 16) + + (buffer[3] << 24); + left -= 4; + buffer += 4; + mv_sdio_write_fifo(sc, data); + } + } else { + while (left > 3) { + data = *((uint32_t *)buffer); + left -= 4; + buffer += 4; + mv_sdio_write_fifo(sc, data); + } + } + /* Handle uneven size case. */ + if (left > 0) { + data = 0; + while (left > 0) { + data <<= 8; + data += *(buffer++); + left--; + } + mv_sdio_write_fifo(sc, data); + } +} + +static int +mv_sdio_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) +{ + struct mv_sdio_softc *sc; + struct mmc_host *host; + + sc = device_get_softc(dev); + host = device_get_ivars(child); + + switch (index) { + case MMCBR_IVAR_BUS_MODE: + *(int *)result = host->ios.bus_mode; + break; + case MMCBR_IVAR_BUS_WIDTH: + *(int *)result = host->ios.bus_width; + break; + case MMCBR_IVAR_CHIP_SELECT: + *(int *)result = host->ios.chip_select; + break; + case MMCBR_IVAR_CLOCK: + *(int *)result = host->ios.clock; + break; + case MMCBR_IVAR_F_MIN: + *(int *)result = host->f_min; + break; + case MMCBR_IVAR_F_MAX: + *(int *)result = host->f_max; + break; + case MMCBR_IVAR_HOST_OCR: + *(int *)result = host->host_ocr; + break; + case MMCBR_IVAR_MODE: + *(int *)result = host->mode; + break; + case MMCBR_IVAR_OCR: + *(int *)result = host->ocr; + break; + case MMCBR_IVAR_POWER_MODE: + *(int *)result = host->ios.power_mode; + break; + case MMCBR_IVAR_VDD: + *(int *)result = host->ios.vdd; + break; + case MMCBR_IVAR_CAPS: + *(int *)result = host->caps; + break; + case MMCBR_IVAR_TIMING: + *(int *)result = host->ios.timing; + break; + case MMCBR_IVAR_MAX_DATA: + mtx_lock(&sc->sc_mtx); + /* Return maximum number of blocks the driver can handle. */ + if (sc->sc_use_dma) + *(int *)result = (sc->sc_dma_size / + MV_SDIO_BLOCK_SIZE); + else + *(int *)result = MV_SDIO_BLOCKS_MAX; + mtx_unlock(&sc->sc_mtx); + break; + default: + return (EINVAL); + } + + return (0); +} + +static int +mv_sdio_write_ivar(device_t dev, device_t child, int index, uintptr_t value) +{ + struct mmc_host *host; + + host = device_get_ivars(child); + + switch (index) { + case MMCBR_IVAR_BUS_MODE: + host->ios.bus_mode = value; + break; + case MMCBR_IVAR_BUS_WIDTH: + host->ios.bus_width = value; + break; + case MMCBR_IVAR_CHIP_SELECT: + host->ios.chip_select = value; + break; + case MMCBR_IVAR_CLOCK: + host->ios.clock = value; + break; + case MMCBR_IVAR_MODE: + host->mode = value; + break; + case MMCBR_IVAR_OCR: + host->ocr = value; + break; + case MMCBR_IVAR_POWER_MODE: + host->ios.power_mode = value; + break; + case MMCBR_IVAR_VDD: + host->ios.vdd = value; + break; + case MMCBR_IVAR_TIMING: + host->ios.timing = value; + break; + case MMCBR_IVAR_CAPS: + case MMCBR_IVAR_HOST_OCR: + case MMCBR_IVAR_F_MIN: + case MMCBR_IVAR_F_MAX: + case MMCBR_IVAR_MAX_DATA: + default: + /* Instance variable not writable. */ + return (EINVAL); + } + + return (0); +} + diff --git a/sys/arm/mv/mv_sdio.h b/sys/arm/mv/mv_sdio.h new file mode 100644 index 0000000..b54b59d --- /dev/null +++ b/sys/arm/mv/mv_sdio.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2008 Marvell Semiconductors, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _MVSDMMC_INCLUDE +#define _MVSDMMC_INCLUDE + + +#define MVSDMMC_DMA_SIZE 65536 + + + +/* + * The base MMC clock rate + */ + +#define MVSDMMC_CLOCKRATE_MIN 100000 +#define MVSDMMC_CLOCKRATE_MAX 50000000 + +#define MVSDMMC_BASE_FAST_CLOCK 200000000 + + +/* + * SDIO register + */ + +#define MV_SDIO_DMA_ADDRL 0x000 +#define MV_SDIO_DMA_ADDRH 0x004 +#define MV_SDIO_BLK_SIZE 0x008 +#define MV_SDIO_BLK_COUNT 0x00c +#define MV_SDIO_CMD 0x01c +#define MV_SDIO_CMD_ARGL 0x010 +#define MV_SDIO_CMD_ARGH 0x014 +#define MV_SDIO_XFER 0x018 +#define MV_SDIO_HOST_SR 0x048 +#define MV_SDIO_HOST_CR 0x050 +#define MV_SDIO_SW_RESET 0x05c +#define MV_SDIO_IRQ_SR 0x060 +#define MV_SDIO_EIRQ_SR 0x064 +#define MV_SDIO_IRQ_SR_EN 0x068 +#define MV_SDIO_EIRQ_SR_EN 0x06c +#define MV_SDIO_IRQ_EN 0x070 +#define MV_SDIO_EIRQ_EN 0x074 +#define MV_SDIO_AUTOCMD12_ARGL 0x084 +#define MV_SDIO_AUTOCMD12_ARGH 0x088 +#define MV_SDIO_AUTOCMD12 0x08c +#define MV_SDIO_CLK_DIV 0x128 +#define MV_SDIO_FIFO 0xa2100 /* FIXME!!! */ + +#define MV_SDIO_RSP(i) (0x020 + ((i)<<2)) +#define MV_SDIO_AUTOCMD12_RSP(i) (0x090 + ((i)<<2)) + +/* + * SDIO Status-Register + */ +#define MV_SDIO_HOST_SR_CARD_BUSY (1<<1) +#define MV_SDIO_HOST_SR_FIFO_EMPTY (1<<13) + + + +/* + * SDIO_CMD + */ +#define MV_SDIO_CMD_RSP_NONE (0 << 0) +#define MV_SDIO_CMD_RSP_136 (1 << 0) +#define MV_SDIO_CMD_RSP_48 (2 << 0) +#define MV_SDIO_CMD_RSP_48_BUSY (3 << 0) +#define MV_SDIO_CMD_DATA_CRC16 (1<<2) +#define MV_SDIO_CMD_CRC7 (1<<3) +#define MV_SDIO_CMD_INDEX_CHECK (1<<4) +#define MV_SDIO_CMD_DATA_PRESENT (1<<5) +#define MV_SDIO_CMD_UNEXPECTED_RSP (1<<7) +#define MV_SDIO_CMD_INDEX(x) ( (x) << 8 ) + + +/* + * SDIO_XFER_MODE + */ +#define MV_SDIO_XFER_STOP_CLK (1 << 5) +#define MV_SDIO_XFER_TO_HOST (1 << 4) +#define MV_SDIO_XFER_PIO (1 << 3) +#define MV_SDIO_XFER_AUTOCMD12 (1 << 2) +#define MV_SDIO_XFER_SW_WR_EN (1 << 1) + +/* + * SDIO_HOST_CTRL + */ +#define MV_SDIO_HOST_CR_PUSHPULL (1 << 0) +#define MV_SDIO_HOST_CR_MMC (3 << 1) +#define MV_SDIO_HOST_CR_BE (1 << 3) +#define MV_SDIO_HOST_CR_4BIT (1 << 9) +#define MV_SDIO_HOST_CR_HIGHSPEED (1 << 10) + +#define MV_SDIO_HOST_CR_TMOVAL(x) ((x) << 11) +#define MV_SDIO_HOST_CR_TMO ( 1 << 15 ) + +/* + * NORmal status bits + */ + + +#define MV_SDIO_IRQ_ERR (1<<15) +#define MV_SDIO_IRQ_UNEXPECTED_RSP (1<<14) +#define MV_SDIO_IRQ_AUTOCMD12 (1<<13) +#define MV_SDIO_IRQ_SUSPENSE_ON_IRQ_EN (1<<12) +#define MV_SDIO_IRQ_IMB_FIFO_WORD_AVAIL (1<<11) +#define MV_SDIO_IRQ_IMB_FIFO_WORD_FILLED (1<<10) +#define MV_SDIO_IRQ_READ_WAIT (1<<9) +#define MV_SDIO_IRQ_CARD_EVENT (1<<8) +#define MV_SDIO_IRQ_RX_FULL (1<<5) +#define MV_SDIO_IRQ_TX_EMPTY (1<<4) +#define MV_SDIO_IRQ_DMA (1<<3) +#define MV_SDIO_IRQ_BLOCK_GAP (1<<2) +#define MV_SDIO_IRQ_XFER (1<<1) +#define MV_SDIO_IRQ_CMD (1<<0) + +#define MV_SDIO_IRQ_ALL (MV_SDIO_IRQ_CMD | MV_SDIO_IRQ_XFER | MV_SDIO_IRQ_BLOCK_GAP | MV_SDIO_IRQ_DMA | MV_SDIO_IRQ_RX_FULL | MV_SDIO_IRQ_TX_EMPTY | MV_SDIO_IRQ_CARD_EVENT | MV_SDIO_IRQ_READ_WAIT | MV_SDIO_IRQ_IMB_FIFO_WORD_FILLED | MV_SDIO_IRQ_IMB_FIFO_WORD_AVAIL | MV_SDIO_IRQ_SUSPENSE_ON_IRQ_EN | MV_SDIO_IRQ_AUTOCMD12 | MV_SDIO_IRQ_UNEXPECTED_RSP | MV_SDIO_IRQ_ERR ) + +//#define MV_SDIO_IRQ_SR + + +/* + * ERR status bits + */ +#define MV_SDIO_EIRQ_CRC_STAT (1<<14) +#define MV_SDIO_EIRQ_CRC_STARTBIT (1<<13) +#define MV_SDIO_EIRQ_CRC_ENDBIT (1<<12) +#define MV_SDIO_EIRQ_RSP_TBIT (1<<11) +#define MV_SDIO_EIRQ_XFER_SIZE (1<<10) +#define MV_SDIO_EIRQ_CMD_STARTBIT (1<<9) +#define MV_SDIO_EIRQ_AUTOCMD12 (1<<8) +#define MV_SDIO_EIRQ_DATA_ENDBIT (1<<6) +#define MV_SDIO_EIRQ_DATA_CRC16 (1<<5) +#define MV_SDIO_EIRQ_DATA_TMO (1<<4) +#define MV_SDIO_EIRQ_CMD_INDEX (1<<3) +#define MV_SDIO_EIRQ_CMD_ENDBIT (1<<2) +#define MV_SDIO_EIRQ_CMD_CRC7 (1<<1) +#define MV_SDIO_EIRQ_CMD_TMO (1<<0) + +#define MV_SDIO_EIRQ_ALL (MV_SDIO_EIRQ_CMD_TMO | \ + MV_SDIO_EIRQ_CMD_CRC7 | \ + MV_SDIO_EIRQ_CMD_ENDBIT | \ + MV_SDIO_EIRQ_CMD_INDEX | \ + MV_SDIO_EIRQ_DATA_TMO | \ + MV_SDIO_EIRQ_DATA_CRC16 | \ + MV_SDIO_EIRQ_DATA_ENDBIT | \ + MV_SDIO_EIRQ_AUTOCMD12 | \ + MV_SDIO_EIRQ_CMD_STARTBIT |\ + MV_SDIO_EIRQ_XFER_SIZE |\ + MV_SDIO_EIRQ_RSP_TBIT |\ + MV_SDIO_EIRQ_CRC_ENDBIT |\ + MV_SDIO_EIRQ_CRC_STARTBIT |\ + MV_SDIO_EIRQ_CRC_STAT) + +/* AUTOCMD12 register values */ +#define MV_SDIO_AUTOCMD12_BUSY_CHECK (1<<0) +#define MV_SDIO_AUTOCMD12_INDEX_CHECK (1<<1) +#define MV_SDIO_AUTOCMD12_INDEX(x) (x<<8) + +/* Software reset register */ +#define MV_SDIO_SW_RESET_ALL (1<<8) + +/* */ +#define MV_SDIO_SIG_CD 1 +#define MV_SDIO_SIG_WP 2 + +#endif /* _MVSDMMC_INCLUDE */ + diff --git a/sys/boot/uboot/common/main.c b/sys/boot/uboot/common/main.c index 82c86b2..0a5b368 100644 --- a/sys/boot/uboot/common/main.c +++ b/sys/boot/uboot/common/main.c @@ -122,6 +122,7 @@ main(void) struct api_signature *sig = NULL; int i; struct open_file f; + char *ub_currdev; if (!api_search_sig(&sig)) return (-1); @@ -166,6 +167,7 @@ main(void) printf("(%s, %s)\n", bootprog_maker, bootprog_date); meminfo(); + ub_currdev = ub_env_get("currdev"); /* * March through the device switch probing for things. */ @@ -198,8 +200,13 @@ main(void) if (devsw[i] == NULL) panic("No boot device found!"); - env_setenv("currdev", EV_VOLATILE, uboot_fmtdev(&currdev), - uboot_setcurrdev, env_nounset); + if (ub_currdev) { + env_setenv("currdev", EV_VOLATILE, ub_currdev, + uboot_setcurrdev, env_nounset); + } else { + env_setenv("currdev", EV_VOLATILE, uboot_fmtdev(&currdev), + uboot_setcurrdev, env_nounset); + } env_setenv("loaddev", EV_VOLATILE, uboot_fmtdev(&currdev), env_noset, env_nounset); diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c index f101e65..6fcfb32 100644 --- a/sys/dev/mmc/mmc.c +++ b/sys/dev/mmc/mmc.c @@ -67,6 +67,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include + #include "mmcbr_if.h" #include "mmcbus_if.h" @@ -96,11 +98,13 @@ struct mmc_ivars { u_char read_only; /* True when the device is read-only */ u_char bus_width; /* Bus width to use */ u_char timing; /* Bus timing support */ + uint8_t mem_present; /* Is memory present */ u_char high_cap; /* High Capacity card (block addressed) */ uint32_t sec_count; /* Card capacity in 512byte blocks */ uint32_t tran_speed; /* Max speed in normal mode */ uint32_t hs_tran_speed; /* Max speed in high speed mode */ uint32_t erase_sector; /* Card native erase sector size */ + uint8_t sdio_numfunc; /* Number of IO functions */ char card_id_string[64];/* Formatted CID info (serial, MFG, etc) */ }; @@ -159,10 +163,15 @@ static uint32_t mmc_get_bits(uint32_t *bits, int bit_len, int start, int size); static int mmc_highest_voltage(uint32_t ocr); static void mmc_idle_cards(struct mmc_softc *sc); +static int mmc_io_func_enable(struct mmc_softc *sc, uint32_t fn); +static int mmc_io_rw_direct(struct mmc_softc *sc, int wr, uint32_t fn, + uint32_t adr, uint8_t *data); static void mmc_ms_delay(int ms); static void mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard); static void mmc_power_down(struct mmc_softc *sc); static void mmc_power_up(struct mmc_softc *sc); +static int mmc_probe_sdio(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr, + uint8_t *nfunc, uint8_t *mem_present); static void mmc_rescan_cards(struct mmc_softc *sc); static void mmc_scan(struct mmc_softc *sc); static int mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, @@ -470,6 +479,7 @@ mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode, return (0); } +/* CMD0 */ static void mmc_idle_cards(struct mmc_softc *sc) { @@ -494,6 +504,7 @@ mmc_idle_cards(struct mmc_softc *sc) mmc_ms_delay(1); } +/* CMD41 -> CMD55 */ static int mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) { @@ -521,6 +532,7 @@ mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) return (err); } +/* CMD1 */ static int mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) { @@ -548,6 +560,7 @@ mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) return (err); } +/* CMD8 */ static int mmc_send_if_cond(struct mmc_softc *sc, uint8_t vhs) { @@ -600,6 +613,7 @@ mmc_power_down(struct mmc_softc *sc) mmcbr_update_ios(dev); } +/* CMD7 */ static int mmc_select_card(struct mmc_softc *sc, uint16_t rca) { @@ -1042,6 +1056,7 @@ mmc_app_decode_sd_status(uint32_t *raw_sd_status, sd_status->erase_offset = mmc_get_bits(raw_sd_status, 512, 400, 2); } +/* CMD2 */ static int mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid) { @@ -1162,6 +1177,7 @@ mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp) return (err); } +/* CMD3 */ static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp) { @@ -1177,6 +1193,7 @@ mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp) return (err); } +/* CMD13 */ static int mmc_send_status(struct mmc_softc *sc, uint16_t rca, uint32_t *status) { @@ -1223,6 +1240,291 @@ mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard) ivar->read_only ? ", read-only" : ""); } +static int +mmc_io_func_enable(struct mmc_softc *sc, uint32_t fn) +{ + int err, i; + uint8_t funcs; + + /* XXX Check if function number is valid */ + + err = mmc_io_rw_direct(sc, 0, 0, SD_IO_CCCR_FN_READY, &funcs); + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, "Error reading SDIO func ready %d\n", err); + return (err); + } + funcs |= 1 << fn; + err = mmc_io_rw_direct(sc, 1, 0, SD_IO_CCCR_FN_ENABLE, &funcs); + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, "Error writing SDIO func enable %d\n", err); + return (err); + } + + funcs = 0; + for(i=0; i < 10; i++) { + err = mmc_io_rw_direct(sc, 0, 0, SD_IO_CCCR_FN_READY, &funcs); + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, "Error reading SDIO func ready %d\n", err); + return (err); + } + + if (funcs & (1 << fn)) + return 0; + pause("mmc_io_func_enable", 100); + } + + device_printf(sc->dev, "Cannot enable function %d!\n", fn); + return 1; +} + +static int +mmc_io_rw_direct(struct mmc_softc *sc, int wr, uint32_t fn, uint32_t adr, + uint8_t *data) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = SD_IO_RW_DIRECT; + cmd.arg = SD_IO_RW_FUNC(fn) | SD_IO_RW_ADR(adr); + if (wr) + cmd.arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data); + cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + cmd.data = NULL; + + err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + if (err) + return (err); + if (cmd.error) + return (cmd.error); + + if (cmd.resp[0] & R5_COM_CRC_ERROR) + return (MMC_ERR_BADCRC); + if (cmd.resp[0] & (R5_ILLEGAL_COMMAND | R5_FUNCTION_NUMBER)) + return (MMC_ERR_INVALID); + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return (MMC_ERR_FAILED); + + /* Just for information... */ + if (R5_IO_CURRENT_STATE(cmd.resp[0]) != 1) + printf("!!! SDIO state %d\n", R5_IO_CURRENT_STATE(cmd.resp[0])); + + *data = (uint8_t) (cmd.resp[0] & 0xff); + return (MMC_ERR_NONE); +} + +/* CMD52 */ +static uint8_t +mmc_io_read_1(struct mmc_softc *sc, uint32_t fn, uint32_t adr) +{ + int err; + uint8_t val = 0; + + err = mmc_io_rw_direct(sc, 0, fn, adr, &val); + if (err) { + device_printf(sc->dev, "Err reading FN %d addr 0x%08X: %d", + fn, adr, err); + return (0xff); + } + return val; +} + +/* + * Parse Card Information Structure of the SDIO card. + * Both Function 0 CIS and Function 1-7 CIS are supported. + */ +static int +mmc_io_parse_cis(struct mmc_softc *sc, uint8_t func, uint32_t cisptr) +{ + /* + * XXX Need a structure to store all information that we get from CIS! + * But where to place it after that?.. + */ + uint32_t tmp; + + uint8_t tuple_id, tuple_len, func_id; + uint32_t addr, maninfo_p; + uint16_t manufacturer, product; + uint16_t fn0_blksize; + uint8_t max_tran_speed; + uint8_t cis1_major, cis1_minor; + char *cis1_info[4]; + + int start, i, ch, count; + char cis1_info_buf[256]; + + cis1_info[0] = NULL; + cis1_info[1] = NULL; + cis1_info[2] = NULL; + cis1_info[3] = NULL; + memset(cis1_info_buf, 0, 256); + + tmp = 0; + addr = cisptr; + + /* + * XXX Some parts of this code are taken + * from sys/dev/pccard/pccard_cis.c. + * Need to think about making it more abstract. + */ + do { + tuple_id = mmc_io_read_1(sc, 0, addr++); + if (tuple_id == SD_IO_CISTPL_END) + break; + tuple_len = mmc_io_read_1(sc, 0, addr++); + if (tuple_len == 0 && tuple_id != 0x00) { + device_printf(sc->dev, + "Parse error: 0-length tuple %02X\n", tuple_id); + break; + } + + switch (tuple_id) { + case SD_IO_CISTPL_VERS_1: + maninfo_p = addr; + + cis1_major = mmc_io_read_1(sc, 0, maninfo_p); + cis1_minor = mmc_io_read_1(sc, 0, maninfo_p + 1); + + for (count = 0, start = 0, i = 0; + (count < 4) && ((i + 4) < 256); i++) { + ch = mmc_io_read_1(sc, 0, maninfo_p + 2 + i); + if (ch == 0xff) + break; + cis1_info_buf[i] = ch; + if (ch == 0) { + cis1_info[count] = + cis1_info_buf + start; + start = i + 1; + count++; + } + } + + device_printf(sc->dev, "*** Info[0]: %s\n", cis1_info[0]); + device_printf(sc->dev, "*** Info[1]: %s\n", cis1_info[1]); + device_printf(sc->dev, "*** Info[2]: %s\n", cis1_info[2]); + device_printf(sc->dev, "*** Info[3]: %s\n", cis1_info[3]); + break; + + case SD_IO_CISTPL_MANFID: + if (tuple_len < 4) { + device_printf(sc->dev, "MANFID is too short\n"); + break; + } + manufacturer = mmc_io_read_1(sc, 0, addr); + manufacturer |= mmc_io_read_1(sc, 0, addr + 1) << 8; + + product = mmc_io_read_1(sc, 0, addr + 2); + product |= mmc_io_read_1(sc, 0, addr + 3) << 8; + + device_printf(sc->dev, + "*** Vendor %04X, product %04X\n", + manufacturer, product); + + break; + + case SD_IO_CISTPL_FUNCID: + /* Function ID for SDIO devices is always 0x0C */ + if (tuple_len < 1) { + device_printf(sc->dev, "FUNCID is too short\n"); + break; + } + func_id = mmc_io_read_1(sc, 0, addr); + if (func_id != 0x0C) + device_printf(sc->dev, "func_id non-std: %d\n", func_id); + break; + + case SD_IO_CISTPL_FUNCE: + if (tuple_len < 4) { + device_printf(sc->dev, "FUNCE is too short\n"); + break; + } + uint8_t ext_data_type = mmc_io_read_1(sc, 0, addr); + device_printf(sc->dev, "*** Function ext type %d\n", + ext_data_type); + + if (func == 0) { + if (ext_data_type != 0x0) + device_printf(sc->dev, + "funce for func 0 non-std: %d\n", + ext_data_type); + fn0_blksize = mmc_io_read_1(sc, 0, addr + 1); + fn0_blksize |= mmc_io_read_1(sc, 0, addr + 2) << 8; + + max_tran_speed = mmc_io_read_1(sc, 0, addr + 3); + uint8_t max_tran_rate = max_tran_speed & 0x3; + uint8_t timecode = (max_tran_speed >> 3) & 0xF; + + device_printf(sc->dev, + "*** Max tran rate %d, timecode %d\n", + max_tran_rate, timecode); + } else { + /* + * XXX Do we need any information from FUNCE + * for non-0 functions? + */ + device_printf(sc->dev, + "I don't know how to parse FUNCE\n"); + } + + break; + + default: + device_printf(sc->dev, + "*** Skipping tuple ID %02X len %02X\n", + tuple_id, tuple_len); + break; + } + + addr += tuple_len; + tmp++; + } while (tuple_id != SD_IO_CISTPL_END && tmp < 10); + + return 0; +} + +/* + * Parse Card Common Control Register of the SDIO card + */ +static int +mmc_io_parse_cccr(struct mmc_softc *sc) +{ + uint32_t cisptr = 0; + + cisptr = mmc_io_read_1(sc, 0, SD_IO_CCCR_CISPTR); + cisptr |= mmc_io_read_1(sc, 0, SD_IO_CCCR_CISPTR + 1) << 8; + cisptr |= mmc_io_read_1(sc, 0, SD_IO_CCCR_CISPTR + 2) << 16; + + if (cisptr < SD_IO_CIS_START || + cisptr > SD_IO_CIS_START + SD_IO_CIS_SIZE) { + device_printf(sc->dev, "Bad CIS pointer in CCCR: %08X\n", cisptr); + return (-1); + } + + return mmc_io_parse_cis(sc, 0, cisptr); +} + +/* + * Parse Function Basic Register of the given function + */ +static int +mmc_io_parse_fbr(struct mmc_softc *sc, uint8_t func) +{ + uint32_t fbr_addr, cisptr; + + fbr_addr = SD_IO_FBR_START * func + 0x9; + cisptr = mmc_io_read_1(sc, 0, fbr_addr); + cisptr |= mmc_io_read_1(sc, 0, fbr_addr + 1) << 8; + cisptr |= mmc_io_read_1(sc, 0, fbr_addr + 2) << 16; + + if (cisptr < SD_IO_CIS_START || + cisptr > SD_IO_CIS_START + SD_IO_CIS_SIZE) { + device_printf(sc->dev, "Bad CIS pointer in FBR: %08X\n", cisptr); + return (-1); + } + + return mmc_io_parse_cis(sc, func, cisptr); +} + static void mmc_discover_cards(struct mmc_softc *sc) { @@ -1233,11 +1535,48 @@ mmc_discover_cards(struct mmc_softc *sc) device_t child; uint16_t rca = 2; u_char switch_res[64]; + uint8_t nfunc, mem_present; if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing cards\n"); while (1) { - err = mmc_all_send_cid(sc, raw_cid); + /* + * Probe SDIO first, because SDIO cards don't have + * a CID register and won't respond to the CMD2 + */ + mmc_idle_cards(sc); + err = mmc_probe_sdio(sc, 0, NULL, &nfunc, &mem_present); + if (err != MMC_ERR_NONE && err != MMC_ERR_TIMEOUT) { + device_printf(sc->dev, "Error probing SDIO %d\n", err); + break; + } + + /* The card answered OK -> SDIO */ + if (err == MMC_ERR_NONE) { + device_printf(sc->dev, "Detected SDIO card\n"); + ivar = malloc(sizeof(struct mmc_ivars), M_DEVBUF, + M_WAITOK | M_ZERO); + mmc_send_relative_addr(sc, &resp); /* CMD3 */ + ivar->rca = resp >> 16; + err = mmc_select_card(sc, ivar->rca); /* CMD7 */ + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, "Error selecting SDIO %d\n", err); + break; + } + + device_printf(sc->dev, "Get card info\n"); + mmc_io_parse_cccr(sc); + for(i=1; i <= nfunc; i++) { + device_printf(sc->dev, + "Get info for function %d\n", i); + mmc_io_parse_fbr(sc, i); + mmc_io_func_enable(sc, i); + } + if (!mem_present) + return; + } + + err = mmc_all_send_cid(sc, raw_cid); /* Command 2 */ if (err == MMC_ERR_TIMEOUT) break; if (err != MMC_ERR_NONE) { @@ -1491,9 +1830,49 @@ mmc_delete_cards(struct mmc_softc *sc) return (0); } +/* CMD 5 */ +static int +mmc_probe_sdio(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr, uint8_t *nfunc, uint8_t *mem_present) { + struct mmc_command cmd; + int err = MMC_ERR_NONE, i; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = IO_SEND_OP_COND; + cmd.arg = 0; + cmd.flags = MMC_RSP_R4; + cmd.data = NULL; + + for (i = 0; i < 1000; i++) { + err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + break; + if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || + (ocr & MMC_OCR_VOLTAGE) == 0) + break; + err = MMC_ERR_TIMEOUT; + mmc_ms_delay(10); + } + + if (err == MMC_ERR_NONE) { + device_printf(sc->dev, "No timeout: OCR %08X, here are the values:\n", cmd.resp[0]); + if (rocr) + *rocr = cmd.resp[0]; + if (nfunc) + *nfunc = cmd.resp[0] >> 28 & 0x7; + if (mem_present) + *mem_present = cmd.resp[0] >> 27 & 0x1; + + device_printf(sc->dev, "NF: %d\n", cmd.resp[0] >> 28 & 0x7); + device_printf(sc->dev, "MEM: %d\n", cmd.resp[0] >> 27 & 0x1); + } + + return (err); +} + static void mmc_go_discovery(struct mmc_softc *sc) { + uint8_t nfunc, mem_present; uint32_t ocr; device_t dev; int err; @@ -1509,17 +1888,24 @@ mmc_go_discovery(struct mmc_softc *sc) if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing bus\n"); mmc_idle_cards(sc); - err = mmc_send_if_cond(sc, 1); + err = mmc_send_if_cond(sc, 1); /* SD_SEND_IF_COND = 8 */ if ((bootverbose || mmc_debug) && err == 0) device_printf(sc->dev, "SD 2.0 interface conditions: OK\n"); - if (mmc_send_app_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { + if (mmc_probe_sdio(sc, 0, &ocr, &nfunc, &mem_present) == MMC_ERR_NONE) { + device_printf(dev, "SDIO probe OK (OCR: 0x%08x, %d functions, memory: %d)\n", ocr, nfunc, mem_present); + if (nfunc > 0 && mem_present) { + device_printf(sc->dev, "SDIO combo cards are not supported yet"); + return; + } + } else + if (mmc_send_app_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { /* retry 55 -> then 41 */ if (bootverbose || mmc_debug) device_printf(sc->dev, "SD probe: failed\n"); /* * Failed, try MMC */ mmcbr_set_mode(dev, mode_mmc); - if (mmc_send_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { + if (mmc_send_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { /* command 1 */ if (bootverbose || mmc_debug) device_printf(sc->dev, "MMC probe: failed\n"); ocr = 0; /* Failed both, powerdown. */ @@ -1553,9 +1939,11 @@ mmc_go_discovery(struct mmc_softc *sc) * Reselect the cards after we've idled them above. */ if (mmcbr_get_mode(dev) == mode_sd) { - err = mmc_send_if_cond(sc, 1); - mmc_send_app_op_cond(sc, - (err ? 0 : MMC_OCR_CCS) | mmcbr_get_ocr(dev), NULL); + if (mem_present) { + err = mmc_send_if_cond(sc, 1); /* CMD 8 */ + mmc_send_app_op_cond(sc, /* 41 -> 55 */ + (err ? 0 : MMC_OCR_CCS) | mmcbr_get_ocr(dev), NULL); + } } else mmc_send_op_cond(sc, mmcbr_get_ocr(dev), NULL); mmc_discover_cards(sc); @@ -1637,7 +2025,7 @@ mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) return (EINVAL); case MMC_IVAR_DSR_IMP: *result = ivar->csd.dsr_imp; - break; + break; case MMC_IVAR_MEDIA_SIZE: *result = ivar->sec_count; break; @@ -1735,3 +2123,4 @@ DRIVER_MODULE(mmc, at91_mci, mmc_driver, mmc_devclass, NULL, NULL); DRIVER_MODULE(mmc, sdhci_pci, mmc_driver, mmc_devclass, NULL, NULL); DRIVER_MODULE(mmc, sdhci_bcm, mmc_driver, mmc_devclass, NULL, NULL); DRIVER_MODULE(mmc, sdhci_fdt, mmc_driver, mmc_devclass, NULL, NULL); +DRIVER_MODULE(mmc, sdio, mmc_driver, mmc_devclass, NULL, NULL); diff --git a/sys/dev/mmc/mmcioreg.h b/sys/dev/mmc/mmcioreg.h new file mode 100644 index 0000000..840a863 --- /dev/null +++ b/sys/dev/mmc/mmcioreg.h @@ -0,0 +1,95 @@ +/* $OpenBSD: sdmmc_ioreg.h,v 1.4 2007/06/02 01:48:37 uwe Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDMMC_IOREG_H +#define _SDMMC_IOREG_H + +/* SDIO commands */ /* response type */ +#define SD_IO_SEND_OP_COND 5 /* R4 */ +#define SD_IO_RW_DIRECT 52 /* R5 */ +#define SD_IO_RW_EXTENDED 53 /* R5? */ + +/* CMD52 arguments */ +#define SD_ARG_CMD52_READ (0<<31) +#define SD_ARG_CMD52_WRITE (1<<31) +#define SD_ARG_CMD52_FUNC_SHIFT 28 +#define SD_ARG_CMD52_FUNC_MASK 0x7 +#define SD_ARG_CMD52_EXCHANGE (1<<27) +#define SD_ARG_CMD52_REG_SHIFT 9 +#define SD_ARG_CMD52_REG_MASK 0x1ffff +#define SD_ARG_CMD52_DATA_SHIFT 0 +#define SD_ARG_CMD52_DATA_MASK 0xff +#define SD_R5_DATA(resp) ((resp)[0] & 0xff) + +/* CMD53 arguments */ +#define SD_ARG_CMD53_READ (0<<31) +#define SD_ARG_CMD53_WRITE (1<<31) +#define SD_ARG_CMD53_FUNC_SHIFT 28 +#define SD_ARG_CMD53_FUNC_MASK 0x7 +#define SD_ARG_CMD53_BLOCK_MODE (1<<27) +#define SD_ARG_CMD53_INCREMENT (1<<26) +#define SD_ARG_CMD53_REG_SHIFT 9 +#define SD_ARG_CMD53_REG_MASK 0x1ffff +#define SD_ARG_CMD53_LENGTH_SHIFT 0 +#define SD_ARG_CMD53_LENGTH_MASK 0x1ff +#define SD_ARG_CMD53_LENGTH_MAX 64 /* XXX should be 511? */ + +/* 48-bit response decoding (32 bits w/o CRC) */ +#define MMC_R4(resp) ((resp)[0]) +#define MMC_R5(resp) ((resp)[0]) + +/* SD R4 response (IO OCR) */ +#define SD_IO_OCR_MEM_READY (1<<31) +#define SD_IO_OCR_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x3) +/* XXX big fat memory present "flag" because we don't know better */ +#define SD_IO_OCR_MEM_PRESENT (0xf<<24) +#define SD_IO_OCR_MASK 0x00fffff0 + +/* Card Common Control Registers (CCCR) */ +#define SD_IO_CCCR_START 0x00000 +#define SD_IO_CCCR_SIZE 0x100 +#define SD_IO_CCCR_FN_ENABLE 0x02 +#define SD_IO_CCCR_FN_READY 0x03 +#define SD_IO_CCCR_INT_ENABLE 0x04 +#define SD_IO_CCCR_CTL 0x06 +#define CCCR_CTL_RES (1<<3) +#define SD_IO_CCCR_BUS_WIDTH 0x07 +#define CCCR_BUS_WIDTH_4 (1<<1) +#define CCCR_BUS_WIDTH_1 (1<<0) +#define SD_IO_CCCR_CISPTR 0x09 /* XXX 9-10, 10-11, or 9-12 */ + +/* Function Basic Registers (FBR) */ +#define SD_IO_FBR_START 0x00100 +#define SD_IO_FBR_SIZE 0x00700 + +/* Card Information Structure (CIS) */ +#define SD_IO_CIS_START 0x01000 +#define SD_IO_CIS_SIZE 0x17000 + +/* CIS tuple codes (based on PC Card 16) */ +#define SD_IO_CISTPL_VERS_1 0x15 +#define SD_IO_CISTPL_MANFID 0x20 +#define SD_IO_CISTPL_FUNCID 0x21 +#define SD_IO_CISTPL_FUNCE 0x22 +#define SD_IO_CISTPL_END 0xff + +/* CISTPL_FUNCID codes */ +/* OpenBSD incorrectly defines 0x0c as FUNCTION_WLAN */ +/* #define SDMMC_FUNCTION_WLAN 0x0c */ +#endif diff --git a/sys/dev/mmc/mmcreg.h b/sys/dev/mmc/mmcreg.h index f454ddb..4b65d91 100644 --- a/sys/dev/mmc/mmcreg.h +++ b/sys/dev/mmc/mmcreg.h @@ -85,6 +85,8 @@ struct mmc_command { #define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY) #define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_PRESENT) +#define MMC_RSP_R4 (MMC_RSP_PRESENT) +#define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC) #define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC) #define MMC_RSP(x) ((x) & MMC_RSP_MASK) @@ -151,6 +153,30 @@ struct mmc_command { #define R1_STATE_PRG 7 #define R1_STATE_DIS 8 +/* + * R5 responses + * + * Types (per SD 2.0 standard) + *e : error bit + *s : status bit + *r : detected and set for the actual command response + *x : Detected and set during command execution. The host can get + * the status by issuing a command with R1 response. + * + * Clear Condition (per SD 2.0 standard) + *a : according to the card current state. + *b : always related to the previous command. reception of a valid + * command will clear it (with a delay of one command). + *c : clear by read + */ +#define R5_COM_CRC_ERROR (1u << 15)/* er, b */ +#define R5_ILLEGAL_COMMAND (1u << 14)/* er, b */ +#define R5_IO_CURRENT_STATE_MASK (3u << 12)/* s, b */ +#define R5_IO_CURRENT_STATE(x) (((x) & R5_IO_CURRENT_STATE_MASK) >> 12) +#define R5_ERROR (1u << 11)/* erx, c */ +#define R5_FUNCTION_NUMBER (1u << 9)/* er, c */ +#define R5_OUT_OF_RANGE (1u << 8)/* er, c */ + struct mmc_data { size_t len; /* size of the data */ size_t xfer_len; @@ -181,7 +207,7 @@ struct mmc_request { #define MMC_SET_RELATIVE_ADDR 3 #define SD_SEND_RELATIVE_ADDR 3 #define MMC_SET_DSR 4 - /* reserved: 5 */ +#define IO_SEND_OP_COND 5 #define MMC_SWITCH_FUNC 6 #define MMC_SWITCH_FUNC_CMDS 0 #define MMC_SWITCH_FUNC_SET 1 @@ -335,6 +361,20 @@ struct mmc_request { #define SD_MAX_HS 50000000 +/* + * SDIO Direct & Extended I/O + */ +#define SD_IO_RW_WR (1u << 31) +#define SD_IO_RW_FUNC(x) (((x) & 0x7) << 28) +#define SD_IO_RW_RAW (1u << 27) +#define SD_IO_RW_INCR (1u << 26) +#define SD_IO_RW_ADR(x) (((x) & 0x1FFFF) << 9) +#define SD_IO_RW_DAT(x) (((x) & 0xFF) << 0) +#define SD_IO_RW_LEN(x) (((x) & 0xFF) << 0) + +#define SD_IOE_RW_LEN(x) (((x) & 0x1FF) << 0) +#define SD_IOE_RW_BLK (1u << 27) + /* OCR bits */ /* From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 15:28:01 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id C20104EB for ; Tue, 2 Jul 2013 15:28:01 +0000 (UTC) (envelope-from lists.br@gmail.com) Received: from mail-we0-x22d.google.com (mail-we0-x22d.google.com [IPv6:2a00:1450:400c:c03::22d]) by mx1.freebsd.org (Postfix) with ESMTP id 5B48A146E for ; Tue, 2 Jul 2013 15:28:01 +0000 (UTC) Received: by mail-we0-f173.google.com with SMTP id x54so4405561wes.4 for ; Tue, 02 Jul 2013 08:28:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=mGjYynWlVx8Qnv3XQ1LLxctlCPIzE0Gc9tM5sPs8DZ4=; b=m78LxroZLvOjVFo1R1nykkKx6FfRMMq12u0rZQ48YB6ZKbIM6fTUMNKbtEljdAqgsx GV7Ncy55bP25YAAoMYahMnSSerr3kTErtGetxjEimbgYCN4AlvAOJJu9zr/GYpMCB++9 jXpuSTKyo7DmpeYoyygwKcO+w0zeRkt+ZMSpGRpuwVLiqjAsLAM0PgSvL9yT9xZTR3Ft wtCDeu7De3ModsYIX1KU/IDwDC9VmI6cJlw9OrqXOmMWFpvKBZ/+WJGbunyYsv5c8aKB 1JH/RfZEyPHLGz2Vn1Zl7awCt5yTqbdtXPi5YHT87ByAmJrPGnAMeBz98dKysVx4hmSf +UwQ== MIME-Version: 1.0 X-Received: by 10.180.72.132 with SMTP id d4mr2012361wiv.25.1372778880465; Tue, 02 Jul 2013 08:28:00 -0700 (PDT) Received: by 10.216.22.196 with HTTP; Tue, 2 Jul 2013 08:28:00 -0700 (PDT) In-Reply-To: <18a9b686d7f49d3773ad63eb853b1c88.squirrel@arroway.org> References: <20130701152313.60982@relay.ibs.dn.ua> <20130701220301.1636@relay.ibs.dn.ua> <20130702085213.52064@relay.ibs.dn.ua> <18a9b686d7f49d3773ad63eb853b1c88.squirrel@arroway.org> Date: Tue, 2 Jul 2013 12:28:00 -0300 Message-ID: Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? From: Luiz Otavio O Souza To: Nenhum_de_Nos Content-Type: text/plain; charset=ISO-8859-1 X-Content-Filtered-By: Mailman/MimeDel 2.1.14 Cc: freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 15:28:01 -0000 On 2 July 2013 08:41, Nenhum_de_Nos wrote: > Hi all, > > I've talked to Luiz some time ago, but I had no time to invest in > struggling with the serial > interface. > > As I said before, I have a 1043ND and would really like to see it running > FreeBSD. Imagine this > hardware running pfSense ? this would be the dlink killer ;) > > do I need to upload it to the hardware to tinkle with the build script ? > First of all I'd like to > help this way, as my shell skills are better then my coding skills :) > > Hi Matheus, If i'm not mistaken you can use the web interface to write a proper generated image to flash. But if anything goes wrong you won't be able to debug without the console access. There are a few scripts to cross build these images (zrouter, adrian's scripts) which you can start with. For pfSense I'm not sure if we have enough RAM on wr1043. I've a brand new WR1043 (never plugged in). If you want, contact me in private and i can provide the help you need to solder the console header on yours, or we can just exchange our units and i'll send mine with console headers (and even with FreeBSD installed). Luiz From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 17:10:31 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 69C1FC0E; Tue, 2 Jul 2013 17:10:31 +0000 (UTC) (envelope-from mavbsd@gmail.com) Received: from mail-bk0-x233.google.com (mail-bk0-x233.google.com [IPv6:2a00:1450:4008:c01::233]) by mx1.freebsd.org (Postfix) with ESMTP id 9DB761AC6; Tue, 2 Jul 2013 17:10:30 +0000 (UTC) Received: by mail-bk0-f51.google.com with SMTP id ji1so2462051bkc.24 for ; Tue, 02 Jul 2013 10:10:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type:content-transfer-encoding; bh=N8FbfpAnhPiIzSiLA+du3iexRP16dXdjqDozpzVkXBg=; b=vuQiKR9sryh2VhVAK5LoCQMFP3hHy/8s5K2CrbzRRF4mK1WmKuVhCOhnDFWtD8C6Of q4zug7Lmzd77J8W5WSZnrnW3J9A+ggfm6NchkI2uAFzjKyQZ0H8rX6/zrFojLqgWp74c l3IDS06f/xmgDXYqPF/DR6csRcomFKuAiYzJNPG28M8qDT6gWjgOG1NlIcF/Q0RQopNn X1f4tlnF8rQ4u/coJbE/qTTL2nZgKp2USYjSbn3jpvS0YQyNaCFdD3tmRab+cklWBYrb +C4/vjnkQeBmd/wbTRSsqs6yTlDUzw9anc48njPz3yCmtXt5RzKNZODUgTuZPwmmcmiH t+Jg== X-Received: by 10.205.3.5 with SMTP id nw5mr4099615bkb.137.1372785029596; Tue, 02 Jul 2013 10:10:29 -0700 (PDT) Received: from mavbook.mavhome.dp.ua (mavhome.mavhome.dp.ua. [213.227.240.37]) by mx.google.com with ESMTPSA id de17sm11798840bkb.5.2013.07.02.10.10.27 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 02 Jul 2013 10:10:28 -0700 (PDT) Sender: Alexander Motin Message-ID: <51D3097A.8010601@FreeBSD.org> Date: Tue, 02 Jul 2013 20:10:18 +0300 From: Alexander Motin User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:17.0) Gecko/20130616 Thunderbird/17.0.6 MIME-Version: 1.0 To: Ilya Bakulin Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug References: <20130702145905.GA1847@olymp.kibab.com> In-Reply-To: <20130702145905.GA1847@olymp.kibab.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 17:10:31 -0000 On 02.07.2013 17:59, Ilya Bakulin wrote: > Hi list, > I'm currently developing a SDIO driver for the Globalscale Dreamplug. > I have taken SDIO patch for Marvell SoC from [1]. > After that I have written some SDIO-related code in sys/dev/mmc/mmc.c, > using OpenBSD SDIO code and the patch from Ben Gray ([2]) as a starting point. > > I have taken Warner's wish to have SDIO code in MMC bus into account, so there > is no extra layer of abstraction in my code, SDIO devices will attach directly > to MMC bus. This makes possible to implement combo cards support in the future, > although I don't support them in my code atm. > > What is already implemented: > * SDIO card detection; > * CIS reading, both common CIS and individual functions' CIS; > * Function enable. > > My questions, need answers before I can move further: > * Where should I store information retrieved from the CIS? > As far as I understand, I should use mmc_ivars structure for that. > But in SDIO case the relationship between MMC bus and SDIO card is 1:1, > and storing the information about the card in mmc_softc sounds like > a good idea -- then I can pass only mmc_softc structure to all functions > that need to work with the attached SDIO card. I think SD world is a terrible mess by itself. I would like to not add more. Functions that suppose card access should take card-specific structure or device as an argument, not a bus ones. > * Should I add any methods to the existing interface files? > > * Are there any devices on the market that use SDIO interface and which > chipsets are supported in FreeBSD? Any Atheros devices? > Adrian, what do you think? > I have only Dreamplug with Marvell SDIO-based WLAN chip, that doesn't have > an opensource driver even for Linux... Recently I've bought EyeFi card hoping it is combined SD+SDIO, but seems like card's WiFi part is completely autonomous and controlled via file access on storage and not really SDIO. I would try to look for SDIO Bluetooth card. I think such ones still could be found on eBay, and I think there are some specifications for that. Though I've never looked inside. > [1] http://people.freebsd.org/~raj/misc/mv_sdio.c > [2] http://lists.freebsd.org/pipermail/freebsd-arm/2012-June/003543.html -- Alexander Motin From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 18:20:17 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 1EF7E834; Tue, 2 Jul 2013 18:20:17 +0000 (UTC) (envelope-from jkwilborn@gmail.com) Received: from mail-pa0-x232.google.com (mail-pa0-x232.google.com [IPv6:2607:f8b0:400e:c03::232]) by mx1.freebsd.org (Postfix) with ESMTP id E738A1E1A; Tue, 2 Jul 2013 18:20:16 +0000 (UTC) Received: by mail-pa0-f50.google.com with SMTP id fb1so6617124pad.9 for ; Tue, 02 Jul 2013 11:20:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=I0VFtTJUMWqpgs8ozlGGkL53SsP2EcVSjEgXhyKOGj0=; b=gY2A/eYFyp627TQxZhv9+r/yljGaGUk+geRfJW+w/30HLdTFOVQ2bUH8aUqQadl2YG wp4wB/2KtnpXnRWHQYLw+/kesvqiZh3+v8VcTc0ouqrCuqGdli9tfktMrVbsXdNdhjV1 swzIeCFwMqLYCbNXlWfY9Ad2ksteR5rf0CoIVHyg5CdFTWtp/F8YmtFmpYQoi8r3Fm24 PeEl+P+E+jiaCktvOMfAE7iqCpC73ohdt0uXQj8cjOQaWQa/uwwlAhQTejzVovkBAjA2 HUMoRcpkOothrI9NLCpa3kuuInIyfyDnx419yNAPrgAlbLWX3uEFQoANjdwFy9TNTv3a QEhw== MIME-Version: 1.0 X-Received: by 10.68.50.69 with SMTP id a5mr30575816pbo.122.1372789216736; Tue, 02 Jul 2013 11:20:16 -0700 (PDT) Received: by 10.66.26.241 with HTTP; Tue, 2 Jul 2013 11:20:16 -0700 (PDT) In-Reply-To: <51D3097A.8010601@FreeBSD.org> References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> Date: Tue, 2 Jul 2013 11:20:16 -0700 Message-ID: Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug From: Jack Wilborn To: Alexander Motin Content-Type: text/plain; charset=ISO-8859-1 X-Content-Filtered-By: Mailman/MimeDel 2.1.14 Cc: freebsd-arm@freebsd.org, Ilya Bakulin , freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 18:20:17 -0000 Nice, how do we include this code in our builds? How is it invoked? Main question is that are these structures in an area that is protected so that only root can modify them? I don't know enough about about SD cards to know if they are alike in the communications to them. I'd like to see more about this and see it in the test bed to give you more feedback. Having taught C for 15 years, I'm ok with reading and understanding the code, but to make it usable is the bottom line. Nice work, I'm sure it would be an asset to all of us. I'm a little groggy about this so if I missed anything, please overlook it. I like it! Jack On Tue, Jul 2, 2013 at 10:10 AM, Alexander Motin wrote: > On 02.07.2013 17:59, Ilya Bakulin wrote: > >> Hi list, >> I'm currently developing a SDIO driver for the Globalscale Dreamplug. >> I have taken SDIO patch for Marvell SoC from [1]. >> After that I have written some SDIO-related code in sys/dev/mmc/mmc.c, >> using OpenBSD SDIO code and the patch from Ben Gray ([2]) as a starting >> point. >> >> I have taken Warner's wish to have SDIO code in MMC bus into account, so >> there >> is no extra layer of abstraction in my code, SDIO devices will attach >> directly >> to MMC bus. This makes possible to implement combo cards support in the >> future, >> although I don't support them in my code atm. >> >> What is already implemented: >> * SDIO card detection; >> * CIS reading, both common CIS and individual functions' CIS; >> * Function enable. >> >> My questions, need answers before I can move further: >> * Where should I store information retrieved from the CIS? >> As far as I understand, I should use mmc_ivars structure for that. >> But in SDIO case the relationship between MMC bus and SDIO card is >> 1:1, >> and storing the information about the card in mmc_softc sounds like >> a good idea -- then I can pass only mmc_softc structure to all >> functions >> that need to work with the attached SDIO card. >> > > I think SD world is a terrible mess by itself. I would like to not add > more. Functions that suppose card access should take card-specific > structure or device as an argument, not a bus ones. > > > * Should I add any methods to the existing interface files? >> >> * Are there any devices on the market that use SDIO interface and which >> chipsets are supported in FreeBSD? Any Atheros devices? >> Adrian, what do you think? >> I have only Dreamplug with Marvell SDIO-based WLAN chip, that doesn't >> have >> an opensource driver even for Linux... >> > > Recently I've bought EyeFi card hoping it is combined SD+SDIO, but seems > like card's WiFi part is completely autonomous and controlled via file > access on storage and not really SDIO. > > I would try to look for SDIO Bluetooth card. I think such ones still could > be found on eBay, and I think there are some specifications for that. > Though I've never looked inside. > > > [1] http://people.freebsd.org/~**raj/misc/mv_sdio.c >> [2] http://lists.freebsd.org/**pipermail/freebsd-arm/2012-** >> June/003543.html >> > > -- > Alexander Motin > > ______________________________**_________________ > freebsd-arm@freebsd.org mailing list > http://lists.freebsd.org/**mailman/listinfo/freebsd-arm > To unsubscribe, send any mail to "freebsd-arm-unsubscribe@**freebsd.org > " > From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 19:21:20 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 8E3FF6D8; Tue, 2 Jul 2013 19:21:20 +0000 (UTC) (envelope-from ilya@bakulin.de) Received: from olymp.kibab.com (olymp.kibab.com [5.9.14.202]) by mx1.freebsd.org (Postfix) with ESMTP id 51C761077; Tue, 2 Jul 2013 19:21:18 +0000 (UTC) X-DKIM: OpenDKIM Filter v2.5.2 olymp.kibab.com 4CE773F43F DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=bakulin.de; s=default; t=1372792877; bh=9LbXBPNxU1btKkfp/3sQcPdHqVZI9dX3li/NPeOfpjo=; h=Date:From:To:CC:Subject:References:In-Reply-To; b=bOZEJMOf7PTkEj+gVreJP0eyvRkipe+S0/givNffd5+CUy0qDQy3U7g6G4liXhf/i 6/pZgeJzUDI7tPJRV0lRSyy8QNiF5sEMLJx6TinrLOsqI+cadnPUQ6AG4hReY7nAFh vc+SyB8FX+EEJ9ujLyD6nf/QU+uyDHTe5DYuayEY= Message-ID: <51D3282C.1090701@bakulin.de> Date: Tue, 02 Jul 2013 21:21:16 +0200 From: Ilya Bakulin MIME-Version: 1.0 To: Alexander Motin Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> In-Reply-To: <51D3097A.8010601@FreeBSD.org> X-Enigmail-Version: 1.5.1 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Cc: freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 19:21:20 -0000 On 02.07.13 19:10, Alexander Motin wrote: > I think SD world is a terrible mess by itself. I would like to not add > more. Functions that suppose card access should take card-specific > structure or device as an argument, not a bus ones. The problem is that there is a SDIO card which has up to 7 functions, but it itself has some characteristics that are available at function 0. If we add, say, sdio0 device and store this information there, we end up with the hierarchy suggested by Ben Gray a year ago. The SD-specific functions like CSD/CSR operations are also in the mmc.c and considered to be the bus code... Or am I missing something obvious here? > I would try to look for SDIO Bluetooth card. I think such ones still > could be found on eBay, and I think there are some specifications for > that. Though I've never looked inside. The SDIO card found in the Dreamplug has three functions, one of them is Bluetooth. Will try to find some docs / Linux code for that... -- Regards, Ilya Bakulin From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 19:32:43 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id B3C22E76 for ; Tue, 2 Jul 2013 19:32:43 +0000 (UTC) (envelope-from imp@bsdimp.com) Received: from mail-oa0-f52.google.com (mail-oa0-f52.google.com [209.85.219.52]) by mx1.freebsd.org (Postfix) with ESMTP id 7E65510F6 for ; Tue, 2 Jul 2013 19:32:43 +0000 (UTC) Received: by mail-oa0-f52.google.com with SMTP id g12so6965751oah.11 for ; Tue, 02 Jul 2013 12:32:42 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=sender:subject:mime-version:content-type:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to:x-mailer :x-gm-message-state; bh=WJX8nY5FtAUh8XSZVqZRdqmIVL8hRc4NBjKrJ/A0OaQ=; b=Q1ohGeyvYQ+JVDrZ529Q0g7FA2HDFxp/5zJlkedlmBRVGj2PXDcIRYi7xubdeZQy11 8TctV1R45sb5oNsQ1qcfzpSjFfTDMoPEBM78zJ7FjZW5uzLMclwTVLwuyp+dQlJyN3ZA Rfgdq7MiRKI5afE1qOC2ucOGHCxU1RdPb7z3bJHaB6TACnf9pAMk1xloW+DcYMvVjGLs XZyRnOfoQm6UrOBPlTgUbsfeqad9OgbstPvMlKWQ6ie5PflzC09kR2Lp36Bo+nOH6E4F 8PoMTZkFwnxN2bD1BcnZFB7msINcgNH39y5JPXaKKTeRugKQNyUBMWbWsLLob45HBUtT H7Jg== X-Received: by 10.60.54.39 with SMTP id g7mr12329487oep.18.1372793562794; Tue, 02 Jul 2013 12:32:42 -0700 (PDT) Received: from monkey-bot.int.fusionio.com ([209.117.142.2]) by mx.google.com with ESMTPSA id z2sm6163821obi.3.2013.07.02.12.32.41 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 02 Jul 2013 12:32:41 -0700 (PDT) Sender: Warner Losh Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug Mime-Version: 1.0 (Apple Message framework v1085) Content-Type: text/plain; charset=us-ascii From: Warner Losh In-Reply-To: Date: Tue, 2 Jul 2013 13:32:37 -0600 Content-Transfer-Encoding: quoted-printable Message-Id: <67798E6A-3B0E-4C2F-AD0F-7D3FF3B0A127@bsdimp.com> References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> To: Jack Wilborn X-Mailer: Apple Mail (2.1085) X-Gm-Message-State: ALoCoQksKaHqhemMFugQQz4rBa494XvZoGp7aavgto7tqKWEty8AraryGJbjbycNeV3pvA80cA/S Cc: Alexander Motin , Ilya Bakulin , freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 19:32:43 -0000 On Jul 2, 2013, at 12:20 PM, Jack Wilborn wrote: > Nice, how do we include this code in our builds? Apply the patches and build a kernel. > How is it invoked? Boot the kernel with a supported SDIO card. > Main > question is that are these structures in an area that is protected so = that > only root can modify them? All this is kernel-level code. > I don't know enough about about SD cards to know if they are alike in = the > communications to them. They are quite similar. SDIO cards are basically SD cards that also have = non-block-sized transfers and interrupt signaling. > I'd like to see more about this and see it in the > test bed to give you more feedback. Having taught C for 15 years, I'm = ok > with reading and understanding the code, but to make it usable is the > bottom line. Nice work, I'm sure it would be an asset to all of us. >=20 > I'm a little groggy about this so if I missed anything, please = overlook > it. I like it! >=20 > Jack >=20 >=20 > On Tue, Jul 2, 2013 at 10:10 AM, Alexander Motin = wrote: >=20 >> On 02.07.2013 17:59, Ilya Bakulin wrote: >>=20 >>> Hi list, >>> I'm currently developing a SDIO driver for the Globalscale = Dreamplug. >>> I have taken SDIO patch for Marvell SoC from [1]. >>> After that I have written some SDIO-related code in = sys/dev/mmc/mmc.c, >>> using OpenBSD SDIO code and the patch from Ben Gray ([2]) as a = starting >>> point. >>>=20 >>> I have taken Warner's wish to have SDIO code in MMC bus into = account, so >>> there >>> is no extra layer of abstraction in my code, SDIO devices will = attach >>> directly >>> to MMC bus. This makes possible to implement combo cards support in = the >>> future, >>> although I don't support them in my code atm. >>>=20 >>> What is already implemented: >>> * SDIO card detection; >>> * CIS reading, both common CIS and individual functions' CIS; >>> * Function enable. >>>=20 >>> My questions, need answers before I can move further: >>> * Where should I store information retrieved from the CIS? The PC Card bus, which also has a CIS, stores it in the slot that it has = for a card. In PC Card land, the CIS is shared between multiple devices, = so we divide things up accordingly. >>> As far as I understand, I should use mmc_ivars structure for = that. >>> But in SDIO case the relationship between MMC bus and SDIO card = is >>> 1:1, >>> and storing the information about the card in mmc_softc sounds = like >>> a good idea -- then I can pass only mmc_softc structure to all >>> functions >>> that need to work with the attached SDIO card. That's quite similar to how we do it for PC Card and CardBus. >> I think SD world is a terrible mess by itself. I would like to not = add >> more. Functions that suppose card access should take card-specific >> structure or device as an argument, not a bus ones. How is it a mess? >> * Should I add any methods to the existing interface files? >>>=20 >>> * Are there any devices on the market that use SDIO interface and = which >>> chipsets are supported in FreeBSD? Any Atheros devices? >>> Adrian, what do you think? >>> I have only Dreamplug with Marvell SDIO-based WLAN chip, that = doesn't >>> have >>> an opensource driver even for Linux... >>>=20 >>=20 >> Recently I've bought EyeFi card hoping it is combined SD+SDIO, but = seems >> like card's WiFi part is completely autonomous and controlled via = file >> access on storage and not really SDIO. Older versions of the card are SDIO. I have one, somewhere. I'll send it = along if I can find it, if you'd like. >> I would try to look for SDIO Bluetooth card. I think such ones still = could >> be found on eBay, and I think there are some specifications for that. >> Though I've never looked inside. There's a standard SDIO Bluetooth interface, so this would be a good = place to start. Warner >> [1] = http://people.freebsd.org/~**raj/misc/mv_sdio.c >>> [2] http://lists.freebsd.org/**pipermail/freebsd-arm/2012-** >>> = June/003543.html >>>=20 >>=20 >> -- >> Alexander Motin >>=20 >> ______________________________**_________________ >> freebsd-arm@freebsd.org mailing list >> = http://lists.freebsd.org/**mailman/listinfo/freebsd-arm >> To unsubscribe, send any mail to = "freebsd-arm-unsubscribe@**freebsd.org >> " >>=20 > _______________________________________________ > freebsd-embedded@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-embedded > To unsubscribe, send any mail to = "freebsd-embedded-unsubscribe@freebsd.org" From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 19:34:47 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 978EE195 for ; Tue, 2 Jul 2013 19:34:47 +0000 (UTC) (envelope-from imp@bsdimp.com) Received: from mail-ob0-f181.google.com (mail-ob0-f181.google.com [209.85.214.181]) by mx1.freebsd.org (Postfix) with ESMTP id 63D17110D for ; Tue, 2 Jul 2013 19:34:47 +0000 (UTC) Received: by mail-ob0-f181.google.com with SMTP id 16so5955668obc.40 for ; Tue, 02 Jul 2013 12:34:41 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=sender:subject:mime-version:content-type:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to:x-mailer :x-gm-message-state; bh=jHnLEivTa4P2sL7H+sO7zbu56z0j64Agl37Klu1lQq0=; b=O/WQPAkfakOO+MGUoa9A2WBWHBzG69wuxKTDgUUn09pH7ch3auNBng8vop0OyRUSFX 0uXxx0zFDFjUEJYGcE7fC4WmrKSL9OOg9UEztiZrshZ70Pz1k0/31QDlVDXJWQkqYXSw pukFpnbBDAFgLWnxUo7ZTk0XRyGNesQEAHyZVxelj7WOPsOu+prmzMe21zDIyon9GUhJ ipQWlUm+82XEBojd6+aF3Dnb7MIgRHGvjbx89tP/DW+G8iqBGTWBfQYLAdJrFck1c6np BHRUzNLfB4M6NXyaf0r4qqxOz0hy69bMxFWBYyN9pz5uKz0vNTyNSL7xFaP2kglqxh2E yC7w== X-Received: by 10.182.61.73 with SMTP id n9mr13897130obr.86.1372793681296; Tue, 02 Jul 2013 12:34:41 -0700 (PDT) Received: from monkey-bot.int.fusionio.com ([209.117.142.2]) by mx.google.com with ESMTPSA id rs4sm6174374obc.10.2013.07.02.12.34.39 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 02 Jul 2013 12:34:40 -0700 (PDT) Sender: Warner Losh Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug Mime-Version: 1.0 (Apple Message framework v1085) Content-Type: text/plain; charset=us-ascii From: Warner Losh In-Reply-To: <51D3282C.1090701@bakulin.de> Date: Tue, 2 Jul 2013 13:34:37 -0600 Content-Transfer-Encoding: 7bit Message-Id: References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> <51D3282C.1090701@bakulin.de> To: Ilya Bakulin X-Mailer: Apple Mail (2.1085) X-Gm-Message-State: ALoCoQkC44XKke3EtV8ke8MHdhVEijuE2JcivqRTG6PutD1WXJTzg8y9JPdwltouEa64v6lboWRe Cc: Alexander Motin , freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 19:34:47 -0000 On Jul 2, 2013, at 1:21 PM, Ilya Bakulin wrote: > On 02.07.13 19:10, Alexander Motin wrote: >> I think SD world is a terrible mess by itself. I would like to not add >> more. Functions that suppose card access should take card-specific >> structure or device as an argument, not a bus ones. > The problem is that there is a SDIO card which has up to 7 functions, > but it itself has some characteristics that are available at function 0. > If we add, say, sdio0 device and store this information there, we end up > with > the hierarchy suggested by Ben Gray a year ago. Yea, and I didn't like that at all. It violates the FreeBSD device model. > The SD-specific functions like CSD/CSR operations are also in the mmc.c > and considered to be the bus code... All this code is for device enumeration, which belongs in the bus layer. > Or am I missing something obvious here? > >> I would try to look for SDIO Bluetooth card. I think such ones still >> could be found on eBay, and I think there are some specifications for >> that. Though I've never looked inside. > > The SDIO card found in the Dreamplug has three functions, one of them is > Bluetooth. > Will try to find some docs / Linux code for that... I'll see if I can dig mine up as well. This sounds like a fun project.. I'll review the actual code here in a bit. Warner From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 19:45:39 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 1A990B90; Tue, 2 Jul 2013 19:45:39 +0000 (UTC) (envelope-from mavbsd@gmail.com) Received: from mail-ee0-x229.google.com (mail-ee0-x229.google.com [IPv6:2a00:1450:4013:c00::229]) by mx1.freebsd.org (Postfix) with ESMTP id 7DAAA11CF; Tue, 2 Jul 2013 19:45:38 +0000 (UTC) Received: by mail-ee0-f41.google.com with SMTP id d17so2995643eek.28 for ; Tue, 02 Jul 2013 12:45:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type:content-transfer-encoding; bh=cglrxEA9Gr2Hefy+5nD/JHGy4hL7t7RS0FlY+960278=; b=x24VgAQoPHlaEGTfydqzCx0P2A+GyMrZ439Q48ompBCgMEL6fjErBT2G3RJSpgWxDP g5wGPbHPOws6at3y4+bITWDZFRHy/E9I/Y6CF9rcAfQI5N9tO9crkilxKf53lBOQG6GA 8+jhGbHOQHQKIA8LqGvQwejIlXR+OVAO57crl5hB/BvkiZYSd7GMxy1XWNk0aj3noVWU P0FWGoBC9NI3JHX9oby2LXKkm/sh1l9DOdYvtsn/EtNya4L5s4GL05Xcpy59PqKhaxZF sa0sbYmGA9Qx6+Ny+IEE/uhdCkw9F+Nwm3LuYC1Li9oTXHMGwL/2EWG7cFgdmYnyJ5ZG 88hg== X-Received: by 10.14.101.13 with SMTP id a13mr27838555eeg.86.1372794337495; Tue, 02 Jul 2013 12:45:37 -0700 (PDT) Received: from mavbook.mavhome.dp.ua (mavhome.mavhome.dp.ua. [213.227.240.37]) by mx.google.com with ESMTPSA id m1sm38763742eex.17.2013.07.02.12.45.35 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 02 Jul 2013 12:45:36 -0700 (PDT) Sender: Alexander Motin Message-ID: <51D32DDD.7030400@FreeBSD.org> Date: Tue, 02 Jul 2013 22:45:33 +0300 From: Alexander Motin User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:17.0) Gecko/20130616 Thunderbird/17.0.6 MIME-Version: 1.0 To: Ilya Bakulin Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> <51D3282C.1090701@bakulin.de> In-Reply-To: <51D3282C.1090701@bakulin.de> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 19:45:39 -0000 On 02.07.2013 22:21, Ilya Bakulin wrote: > On 02.07.13 19:10, Alexander Motin wrote: >> I think SD world is a terrible mess by itself. I would like to not add >> more. Functions that suppose card access should take card-specific >> structure or device as an argument, not a bus ones. > The problem is that there is a SDIO card which has up to 7 functions, > but it itself has some characteristics that are available at function 0. > If we add, say, sdio0 device and store this information there, we end up > with > the hierarchy suggested by Ben Gray a year ago. > The SD-specific functions like CSD/CSR operations are also in the mmc.c > and considered to be the bus code... > > Or am I missing something obvious here? That is why I am telling it is a big mess. I don't remember SDIO initialization sequence now, but as I can see, for SD cards CSD includes information about speed, while SCR includes information about bus width, that are probably parts that should be negotiated by the bus, not specific peripheral driver. >> I would try to look for SDIO Bluetooth card. I think such ones still >> could be found on eBay, and I think there are some specifications for >> that. Though I've never looked inside. > > The SDIO card found in the Dreamplug has three functions, one of them is > Bluetooth. > Will try to find some docs / Linux code for that... https://www.sdcard.org/downloads/pls/simplified_specs/ -- "SDIO Bluetooth Type A Simplified Specification". And for some money it should probably possible to get full one, if needed. -- Alexander Motin From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 20:09:48 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id B014CFBE; Tue, 2 Jul 2013 20:09:48 +0000 (UTC) (envelope-from ilya@bakulin.de) Received: from olymp.kibab.com (olymp.kibab.com [5.9.14.202]) by mx1.freebsd.org (Postfix) with ESMTP id 71AA812B7; Tue, 2 Jul 2013 20:09:47 +0000 (UTC) X-DKIM: OpenDKIM Filter v2.5.2 olymp.kibab.com 5921F3F480 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=bakulin.de; s=default; t=1372795786; bh=vwhkoA1keqN8F3agTW1fmCMSrODtNkEzU+qdgVJtGEM=; h=Date:From:To:CC:Subject:References:In-Reply-To; b=ozw9/Bvo2WxtQfm7QpJphLpqbDI6QXm4OoUVKqtHStRNows6TyvI2iLq21LwN6Ve0 KUKQAjxuq4cUWtUxO+/HhEjlNfbg3oaVgXeK3fLM99F/9Y1pIq/WL7syeSSaDGqR6L RQszz5T4AcCtjoX+8GzTaJKqpRjJZ0w4KlDTDl20= Message-ID: <51D3338A.1010304@bakulin.de> Date: Tue, 02 Jul 2013 22:09:46 +0200 From: Ilya Bakulin MIME-Version: 1.0 To: Warner Losh Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> <51D3282C.1090701@bakulin.de> In-Reply-To: X-Enigmail-Version: 1.5.1 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Cc: Alexander Motin , freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 20:09:48 -0000 On 02.07.13 21:34, Warner Losh wrote: > > On Jul 2, 2013, at 1:21 PM, Ilya Bakulin wrote: >> The SDIO card found in the Dreamplug has three functions, one of them is >> Bluetooth. >> Will try to find some docs / Linux code for that... > > I'll see if I can dig mine up as well. This sounds like a fun project.. > Seems like Marvell Bluetooth is not a standard one. The support code for it in the Linux kernel is [1], while generic driver is [2]. Marvell uses a loadable firmware to bring the module to life. The firmware seems to be shared between Wi-Fi and Bluetooth module. Implementing firmware upload seems to be implementable using our standard firmware(9) interface, so I will need to embed the firmware into the kernel. I cannot use loadable modules because I boot my kernel via NFS. Of course, Bluetooth support can be implemented only when the SDIO infrastructure is ready, so this is the highest priority for me atm :-) [1] https://github.com/torvalds/linux/blob/master/drivers/bluetooth/btmrvl_sdio.c [2] https://github.com/torvalds/linux/blob/master/drivers/bluetooth/btsdio.c -- Regards, Ilya Bakulin From owner-freebsd-embedded@FreeBSD.ORG Tue Jul 2 22:18:40 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id EEDBC21E; Tue, 2 Jul 2013 22:18:40 +0000 (UTC) (envelope-from kibab@olymp.kibab.com) Received: from olymp.kibab.com (olymp.kibab.com [5.9.14.202]) by mx1.freebsd.org (Postfix) with ESMTP id B9A911996; Tue, 2 Jul 2013 22:18:39 +0000 (UTC) X-DKIM: OpenDKIM Filter v2.5.2 olymp.kibab.com BE2543F47B DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=bakulin.de; s=default; t=1372803517; bh=Iv0nerWML0jQUS5DQ3EYBpkST273JQO0pWUACRyvkvk=; h=Date:From:To:Cc:Subject:References:In-Reply-To; b=a0U90VYaUK5FPKBGNCx+BsKSGInPB8EU8d+fRYnECOvuZNemqdSOLXQxJ2gCOoP2e jMZa1PAtWc6XbHQBm69UO87Zb0C9U11CttYkdyU4aKzamggym81AVrTCgNf/maoWB0 lMwRrq33pdvqsMLHUGgxs5P+czrcOHy3lhW+uDJ0= Date: Wed, 3 Jul 2013 00:18:37 +0200 From: Ilya Bakulin To: Warner Losh Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug Message-ID: <20130702221837.GA76081@olymp.kibab.com> References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> <67798E6A-3B0E-4C2F-AD0F-7D3FF3B0A127@bsdimp.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <67798E6A-3B0E-4C2F-AD0F-7D3FF3B0A127@bsdimp.com> User-Agent: Mutt/1.5.21 (2010-09-15) Cc: Jack Wilborn , freebsd-arm@freebsd.org, Alexander Motin , freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 02 Jul 2013 22:18:41 -0000 On Tue, Jul 02, 2013 at 01:32:37PM -0600, Warner Losh wrote: > >>> * Where should I store information retrieved from the CIS? > > The PC Card bus, which also has a CIS, stores it in the slot that it has for a card. In PC Card land, the CIS is shared between multiple devices, so we divide things up accordingly. [...] > > That's quite similar to how we do it for PC Card and CardBus. OK, I have modified my code to store per-function information in the tail queue. Function #0 is special in SDIO, so I chose to store its info separately. Here is an updated patch. Please don't blame me much :-) diff --git a/sys/arm/conf/KIBAB-DPLUG b/sys/arm/conf/KIBAB-DPLUG new file mode 100644 index 0000000..033d398 --- /dev/null +++ b/sys/arm/conf/KIBAB-DPLUG @@ -0,0 +1,171 @@ +# Kernel config for GlobalScale Technologies DreamPlug version 1001. +# +# This is for units that are version 10, revision 01, with NOR SPI flash. +# These units are identified with the number "1001" on the S/N label. +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ +# + +ident KIBAB-DPLUG + +include "../mv/kirkwood/std.db88f6xxx" + +makeoptions FDT_DTS_FILE=dreamplug-1001.dts + +makeoptions MODULES_OVERRIDE="" + +options SOC_MV_KIRKWOOD + +options SCHED_4BSD #4BSD scheduler +options INET #InterNETworking +options INET6 #IPv6 communications protocols +options SOFTUPDATES +options CD9660 #ISO 9660 filesystem +options FFS #Berkeley Fast Filesystem +options MSDOSFS #MS DOS File System (FAT, FAT32) +options NULLFS #NULL filesystem +options TMPFS #Efficient memory filesystem +options SYSVSHM #SYSV-style shared memory +options SYSVMSG #SYSV-style message queues +options SYSVSEM #SYSV-style semaphores +options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions +options GEOM_ELI # Disk encryption. +options GEOM_LABEL # Providers labelization. +options GEOM_PART_GPT # GPT partitioning + +# Flattened Device Tree +device fdt +options FDT +options FDT_DTB_STATIC + +# Misc pseudo devices +device bpf #Required for DHCP +device faith #IPv6-to-IPv4 relaying (translation) +device firmware #firmware(9) required for USB wlan +device gif #IPv6 and IPv4 tunneling +device loop #Network loopback +device md #Memory/malloc disk +device pty #BSD-style compatibility pseudo ttys +device random #Entropy device +device tun #Packet tunnel. +device ether #Required for all ethernet devices +device vlan #802.1Q VLAN support +device wlan #802.11 WLAN support + +# cam support for umass and ahci +device scbus +device pass +device da +device cd + +# Serial ports +device uart + +# Networking +device mge # Marvell Gigabit Ethernet controller +device mii +device e1000phy + +# USB +options USB_HOST_ALIGN=32 # Align DMA to cacheline +#options USB_DEBUG # Compile in USB debug support +device usb # Basic usb support +device ehci # USB host controller +device umass # Mass storage +device uhid # Human-interface devices +device rum # Ralink Technology RT2501USB wireless NICs + +# I2C (TWSI) +device iic +device iicbus + +# SATA +device mvs +device ahci + +# SDIO +device mv_sdio +device mmcsd +device mmc + +# Sound +device sound +device snd_uaudio + +#crypto +device cesa # Marvell security engine +device crypto +device cryptodev + +# IPSec +device enc +options IPSEC +options IPSEC_NAT_T +options TCP_SIGNATURE #include support for RFC 2385 + +#PF +device pf +device pflog +device pfsync + +# ALTQ, required for PF +options ALTQ # Basic ALTQ support +options ALTQ_CBQ # Class Based Queueing +options ALTQ_RED # Random Early Detection +options ALTQ_RIO # RED In/Out +options ALTQ_HFSC # Hierarchical Packet Scheduler +options ALTQ_CDNR # Traffic conditioner +options ALTQ_PRIQ # Priority Queueing +options ALTQ_NOPCC # Required if the TSC is unusable +#options ALTQ_DEBUG + +# Debugging +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols +options BREAK_TO_DEBUGGER +options ALT_BREAK_TO_DEBUGGER +options DDB +options KDB +options DIAGNOSTIC +options INVARIANTS #Enable calls of extra sanity checking +options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS #Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed +#options WITNESS_KDB + +# Enable these options for nfs root configured via BOOTP. +options NFSCL #Network Filesystem Client +options NFSLOCKD #Network Lock Manager +options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options BOOTP +options BOOTP_NFSROOT +#options BOOTP_NFSV3 +options BOOTP_WIRED_TO=mge0 + +# If not using BOOTP, use something like one of these... +#options ROOTDEVNAME=\"ufs:/dev/da1a\" +#options ROOTDEVNAME=\"ufs:/dev/da1s1a\" +#options ROOTDEVNAME=\"ufs:/dev/da1p10\" +#options ROOTDEVNAME=\"nfs:192.168.0.254/dreamplug\" + +# To use this configuration with the (rare) model 1001N (nand flash), +# create a kernel config file that looks like this: +# +# include DREAMPLUG-1001 +# nomakeoptions FDT_DTS_FILE +# makeoptions FDT_DTS_FILE=dreamplug-1001N.dts +# device nand diff --git a/sys/arm/conf/KIBAB-DPLUG-NODBG b/sys/arm/conf/KIBAB-DPLUG-NODBG new file mode 100644 index 0000000..cbced4a --- /dev/null +++ b/sys/arm/conf/KIBAB-DPLUG-NODBG @@ -0,0 +1,43 @@ +# Kernel config for GlobalScale Technologies DreamPlug version 1001. +# +# This is for units that are version 10, revision 01, with NOR SPI flash. +# These units are identified with the number "1001" on the S/N label. +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ +# + +ident KIBAB-DPLUG-NODBG + +include KIBAB-DPLUG + +# Do not compile FDT in kernel +nomakeoptions FDT_DTS_FILE +nooptions FDT_DTB_STATIC + +# Debugging +nomakeoptions DEBUG +nooptions BREAK_TO_DEBUGGER +nooptions ALT_BREAK_TO_DEBUGGER +nooptions DDB +nooptions KDB +nooptions DIAGNOSTIC +nooptions INVARIANTS #Enable calls of extra sanity checking +nooptions INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS #Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed +#options WITNESS_KDB diff --git a/sys/arm/conf/KIBAB-DPLUG-PROD b/sys/arm/conf/KIBAB-DPLUG-PROD new file mode 100644 index 0000000..bae61a4 --- /dev/null +++ b/sys/arm/conf/KIBAB-DPLUG-PROD @@ -0,0 +1,33 @@ +# Kernel config for GlobalScale Technologies DreamPlug version 1001. +# +# This is for units that are version 10, revision 01, with NOR SPI flash. +# These units are identified with the number "1001" on the S/N label. +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ +# + + +include KIBAB-DPLUG-NODBG + +ident KIBAB-DPLUG-PROD + +nooptions NFS_ROOT +nooptions BOOTP +nooptions BOOTP_NFSROOT +nooptions BOOTP_WIRED_TO + diff --git a/sys/arm/mv/files.mv b/sys/arm/mv/files.mv index 116356d..88c0b98 100644 --- a/sys/arm/mv/files.mv +++ b/sys/arm/mv/files.mv @@ -32,6 +32,7 @@ arm/mv/mv_sata.c optional ata | atamvsata arm/mv/mv_ts.c standard arm/mv/timer.c standard arm/mv/twsi.c optional iicbus +arm/mv/mv_sdio.c optional mv_sdio dev/cesa/cesa.c optional cesa dev/mge/if_mge.c optional mge diff --git a/sys/arm/mv/mv_sdio.c b/sys/arm/mv/mv_sdio.c new file mode 100644 index 0000000..73faf08 --- /dev/null +++ b/sys/arm/mv/mv_sdio.c @@ -0,0 +1,1670 @@ +/*- + * Copyright (c) 2009 Semihalf, Rafal Czubak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Driver for Marvell Integrated SDIO Host Controller. + * Works stable in DMA mode. PIO mode has problems with large data transfers + * (timeouts). + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "mmcbr_if.h" + +#include "mv_sdio.h" + +/* Minimum DMA segment size. */ +#define MV_SDIO_DMA_SEGMENT_SIZE 4096 + +/* Transferred block size. */ +#define MV_SDIO_BLOCK_SIZE 512 + +/* Maximum number of blocks the controller can handle. */ +#define MV_SDIO_BLOCKS_MAX 65535 + +/* Halfword bit masks used for command response extraction. */ +#define MV_SDIO_RSP48_BM2 0x0002 /* Lower 2 bits. */ +#define MV_SDIO_RSP48_BM6 0x003f /* Lower 6 bits. */ +#define MV_SDIO_RSP48_BM16 0xffff /* 16 bits */ + +/* SDIO aggregated command interrupts */ +#define MV_SDIO_IRQS_CMD (MV_SDIO_IRQ_CMD | MV_SDIO_IRQ_UNEXPECTED_RSP) +#define MV_SDIO_EIRQS_CMD (MV_SDIO_EIRQ_CMD_TMO | MV_SDIO_EIRQ_CMD_CRC7 | \ + MV_SDIO_EIRQ_CMD_ENDBIT | MV_SDIO_EIRQ_CMD_INDEX | \ + MV_SDIO_EIRQ_CMD_STARTBIT | MV_SDIO_EIRQ_RSP_TBIT) + +/* SDIO aggregated data interrupts */ +#define MV_SDIO_IRQS_DATA (MV_SDIO_IRQ_XFER | MV_SDIO_IRQ_TX_EMPTY | \ + MV_SDIO_IRQ_RX_FULL | MV_SDIO_IRQ_DMA | MV_SDIO_IRQ_AUTOCMD12) +#define MV_SDIO_EIRQS_DATA (MV_SDIO_EIRQ_DATA_TMO | \ + MV_SDIO_EIRQ_DATA_CRC16 | MV_SDIO_EIRQ_DATA_ENDBIT | \ + MV_SDIO_EIRQ_AUTOCMD12 | MV_SDIO_EIRQ_XFER_SIZE | \ + MV_SDIO_EIRQ_CRC_ENDBIT | MV_SDIO_EIRQ_CRC_STARTBIT | \ + MV_SDIO_EIRQ_CRC_STAT) + +/* + * Timing configuration. + */ + +/* SDIO controller base clock frequency. */ +#define MV_SDIO_F_BASE 100000000 /* 200 MHz */ + +/* Maximum SD clock frequency. */ +#define MV_SDIO_F_MAX (MV_SDIO_F_BASE / 2) /* 50 MHz */ + +/* Maximum timeout value. */ +#define MV_SDIO_TMO_MAX 0xf + +/* Reset delay in microseconds. */ +#define MV_SDIO_RESET_DELAY 10000 /* 10 ms */ + +/* Empty FIFO polling delay. */ +#define MV_SDIO_FIFO_EMPTY_DELAY 1000 /* 1 ms */ + +/* Delays between operations on multiple blocks. */ +#define MV_SDIO_RD_DELAY 50 /*50*/ /* Read access time. */ +#define MV_SDIO_WR_DELAY 10 /*10*/ /* Write access time. */ + +/* Maximum clock divider value. */ +#define MV_SDIO_CLK_DIV_MAX 0x7ff + +struct mv_sdio_softc { + device_t sc_dev; + device_t sc_child; + + bus_space_handle_t sc_bsh; + bus_space_tag_t sc_bst; + + int sc_use_dma; + bus_dma_tag_t sc_dmatag; + bus_dmamap_t sc_dmamap; + uint8_t *sc_dmamem; + bus_addr_t sc_physaddr; + int sc_mapped; + size_t sc_dma_size; + + struct resource *sc_mem_res; + int sc_mem_rid; + + struct resource *sc_irq_res; + int sc_irq_rid; + void *sc_ihl; + + struct resource *sc_cd_irq_res; + int sc_cd_irq_rid; + void *sc_cd_ihl; + + uint32_t sc_irq_mask; + uint32_t sc_eirq_mask; + + struct task sc_card_task; + struct callout sc_card_callout; + + struct mtx sc_mtx; + + int sc_bus_busy; + int sc_card_present; + struct mmc_host sc_host; + struct mmc_request *sc_req; + struct mmc_command *sc_curcmd; + + uint32_t sc_data_offset; +}; + +/* Read/write data from/to registers.*/ +static uint32_t MV_SDIO_RD4(struct mv_sdio_softc *, bus_size_t); +static void MV_SDIO_WR4(struct mv_sdio_softc *, bus_size_t, uint32_t); + +static int mv_sdio_probe(device_t); +static int mv_sdio_attach(device_t); + +static int mv_sdio_read_ivar(device_t, device_t, int, uintptr_t *); +static int mv_sdio_write_ivar(device_t, device_t, int, uintptr_t); + +static int mv_sdio_update_ios(device_t, device_t); +static int mv_sdio_request(device_t, device_t, struct mmc_request *); +static int mv_sdio_get_ro(device_t, device_t); +static int mv_sdio_acquire_host(device_t, device_t); +static int mv_sdio_release_host(device_t, device_t); + +/* Finalizes active MMC request. */ +static void mv_sdio_finalize_request(struct mv_sdio_softc *); + +/* Initializes controller's registers. */ +static void mv_sdio_init(device_t); + +/* Initializes host structure. */ +static void mv_sdio_init_host(struct mv_sdio_softc *); + +/* Used to add and handle sysctls. */ +static void mv_sdio_add_sysctls(struct mv_sdio_softc *); +static int mv_sdio_sysctl_use_dma(SYSCTL_HANDLER_ARGS); + +/* DMA initialization and cleanup functions. */ +static int mv_sdio_dma_init(struct mv_sdio_softc *); +static void mv_sdio_dma_finish(struct mv_sdio_softc *); + +/* DMA map load callback. */ +static void mv_sdio_getaddr(void *, bus_dma_segment_t *, int, int); + +/* Prepare command/data before transaction. */ +static int mv_sdio_start_command(struct mv_sdio_softc *, struct + mmc_command *); +static int mv_sdio_start_data(struct mv_sdio_softc *, struct mmc_data *); + +/* Finish command after transaction. */ +static void mv_sdio_finish_command(struct mv_sdio_softc *); + +/* Response handling. */ +static void mv_sdio_handle_136bit_resp(struct mv_sdio_softc *); +static void mv_sdio_handle_48bit_resp(struct mv_sdio_softc *, + struct mmc_command *); + +/* Interrupt handler and interrupt helper functions. */ +static void mv_sdio_intr(void *); +static void mv_sdio_cmd_intr(struct mv_sdio_softc *, uint32_t, uint32_t); +static void mv_sdio_data_intr(struct mv_sdio_softc *, uint32_t, uint32_t); +static void mv_sdio_disable_intr(struct mv_sdio_softc *); + +/* Used after card detect interrupt has been handled. */ +static void mv_sdio_card_task(void *, int); + +/* Read/write data from FIFO in PIO mode. */ +static uint32_t mv_sdio_read_fifo(struct mv_sdio_softc *); +static void mv_sdio_write_fifo(struct mv_sdio_softc *, uint32_t); + +/* + * PIO mode handling. + * + * Inspired by sdhci(4) driver routines. + */ +static void mv_sdio_transfer_pio(struct mv_sdio_softc *); +static void mv_sdio_read_block_pio(struct mv_sdio_softc *); +static void mv_sdio_write_block_pio(struct mv_sdio_softc *); + + +static device_method_t mv_sdio_methods[] = { + /* device_if */ + DEVMETHOD(device_probe, mv_sdio_probe), + DEVMETHOD(device_attach, mv_sdio_attach), + + /* Bus interface */ + DEVMETHOD(bus_read_ivar, mv_sdio_read_ivar), + DEVMETHOD(bus_write_ivar, mv_sdio_write_ivar), + + /* mmcbr_if */ + DEVMETHOD(mmcbr_update_ios, mv_sdio_update_ios), + DEVMETHOD(mmcbr_request, mv_sdio_request), + DEVMETHOD(mmcbr_get_ro, mv_sdio_get_ro), + DEVMETHOD(mmcbr_acquire_host, mv_sdio_acquire_host), + DEVMETHOD(mmcbr_release_host, mv_sdio_release_host), + + {0, 0}, +}; + +static driver_t mv_sdio_driver = { + "sdio", + mv_sdio_methods, + sizeof(struct mv_sdio_softc), +}; +static devclass_t mv_sdio_devclass; + +DRIVER_MODULE( sdio, simplebus, mv_sdio_driver, mv_sdio_devclass, 0, 0); + + +static __inline uint32_t +MV_SDIO_RD4(struct mv_sdio_softc *sc, bus_size_t off) +{ + + return (bus_read_4(sc->sc_mem_res, off)); +} + +static __inline void +MV_SDIO_WR4(struct mv_sdio_softc *sc, bus_size_t off, uint32_t val) +{ + + bus_write_4(sc->sc_mem_res, off, val); +} + +static int platform_sdio_slot_signal( int signal ) +{ + switch( signal ) + { + case MV_SDIO_SIG_CD: + { + return -1; + break; + } + case MV_SDIO_SIG_WP: + return 0; + break; + default: + return -1; + break; + } + + return 0; +} + +static int +mv_sdio_probe(device_t dev) +{ + uint32_t device, revision; + + if (!ofw_bus_is_compatible(dev, "mrvl,sdio")) + return (ENXIO); + + + soc_id(&device, &revision); + + switch (device) { + case MV_DEV_88F6281: + break; + default: + return (ENXIO); + } + + device_set_desc(dev, "Marvell Integrated SDIO Host Controller"); + + return (BUS_PROBE_SPECIFIC); +} + +static int +mv_sdio_attach(device_t dev) +{ + struct mv_sdio_softc *sc; + int task_initialized = 0; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); + + /* Allocate memory and interrupt resources. */ + sc->sc_mem_rid = 0; + sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->sc_mem_rid, RF_ACTIVE); + + if (sc->sc_mem_res == NULL) { + device_printf(dev, "Could not allocate memory!\n"); + goto fail; + } + + sc->sc_irq_rid = 0; + sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->sc_irq_rid, RF_ACTIVE); + + if (sc->sc_irq_res == NULL) { + device_printf(dev, "Could not allocate IRQ!\n"); + goto fail; + } + + sc->sc_bst = rman_get_bustag(sc->sc_mem_res); + sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res); + + + /* Initialize host controller's registers. */ + mv_sdio_init(dev); + + /* Try to setup DMA. */ + sc->sc_mapped = 0; /* No DMA buffer is mapped. */ + sc->sc_use_dma = 1; /* DMA mode is preferred to PIO mode. */ + + if (mv_sdio_dma_init(sc) < 0) { + device_printf(dev, "Falling back to PIO mode.\n"); + sc->sc_use_dma = 0; + } + + /* Add sysctls. */ + mv_sdio_add_sysctls(sc); + + if (platform_sdio_slot_signal(MV_SDIO_SIG_CD) != -1) { + /* Check if card is present in the slot. */ + if (platform_sdio_slot_signal(MV_SDIO_SIG_CD) == 1) + sc->sc_card_present = 1; + } + + TASK_INIT(&sc->sc_card_task, 0, mv_sdio_card_task, sc); + callout_init(&sc->sc_card_callout, 1); + task_initialized = 1; + + /* Setup interrupt. */ + if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | + INTR_MPSAFE, NULL, mv_sdio_intr, sc, &sc->sc_ihl) != 0) { + device_printf(dev, "Could not setup interrupt!\n"); + goto fail; + } + + /* Host can be acquired. */ + sc->sc_bus_busy = 0; + + /* + * Attach MMC bus only if the card is in the slot or card detect is + * not supported on the platform. + */ + if ((platform_sdio_slot_signal(MV_SDIO_SIG_CD) == -1) || + sc->sc_card_present) { + sc->sc_child = device_add_child(dev, "mmc", -1); + + if (sc->sc_child == NULL) { + device_printf(dev, "Could not add MMC bus!\n"); + goto fail; + } + + /* Initialize host structure for MMC bus. */ + mv_sdio_init_host(sc); + + device_set_ivars(sc->sc_child, &sc->sc_host); + } + + return (bus_generic_attach(dev)); + +fail: + mv_sdio_dma_finish(sc); + if (task_initialized) { + callout_drain(&sc->sc_card_callout); + taskqueue_drain(taskqueue_swi, &sc->sc_card_task); + } + if (sc->sc_ihl != NULL) + bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_ihl); + if (sc->sc_cd_ihl != NULL) + bus_teardown_intr(dev, sc->sc_cd_irq_res, sc->sc_cd_ihl); + if (sc->sc_irq_res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, + sc->sc_irq_res); + if (sc->sc_cd_irq_res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, sc->sc_cd_irq_rid, + sc->sc_cd_irq_res); + if (sc->sc_mem_res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, + sc->sc_mem_res); + mtx_destroy(&sc->sc_mtx); + return (ENXIO); +} + +static int +mv_sdio_update_ios(device_t brdev, device_t reqdev) +{ + struct mv_sdio_softc *sc; + struct mmc_host *host; + struct mmc_ios *ios; + uint32_t xfer, clk_div, host_cr; + + sc = device_get_softc(brdev); + host = device_get_ivars(reqdev); + ios = &host->ios; + + mtx_lock(&sc->sc_mtx); + + if (ios->power_mode == power_off) + /* Re-initialize the controller. */ + mv_sdio_init(brdev); + + xfer = MV_SDIO_RD4(sc, MV_SDIO_XFER); + + if (ios->clock == 0) { + /* Disable clock. */ + xfer |= MV_SDIO_XFER_STOP_CLK; + MV_SDIO_WR4(sc, MV_SDIO_XFER, xfer); + + /* Set maximum clock divider. */ + MV_SDIO_WR4(sc, MV_SDIO_CLK_DIV, MV_SDIO_CLK_DIV_MAX); + } else { + /* + * Calculate and set clock divider. + * Clock rate value is: + * clock = MV_SDIO_F_BASE / (clk_div + 1) + * Thus we calculate the divider value as: + * clk_div = (MV_SDIO_F_BASE / clock) - 1 + */ + clk_div = (MV_SDIO_F_BASE / ios->clock) - 1; + if (clk_div > MV_SDIO_CLK_DIV_MAX) + clk_div = MV_SDIO_CLK_DIV_MAX; + MV_SDIO_WR4(sc, MV_SDIO_CLK_DIV, clk_div); + + /* Enable clock. */ + xfer &= ~MV_SDIO_XFER_STOP_CLK; + MV_SDIO_WR4(sc, MV_SDIO_XFER, xfer); + } + + host_cr = MV_SDIO_RD4(sc, MV_SDIO_HOST_CR); + + /* Set card type. */ + if (host->mode == mode_mmc) + host_cr |= MV_SDIO_HOST_CR_MMC; /* MMC card. */ + else + host_cr &= ~MV_SDIO_HOST_CR_MMC; /* SD card. */ + + /* Set bus width. */ + if (ios->bus_width == bus_width_4) + host_cr |= MV_SDIO_HOST_CR_4BIT; /* 4-bit bus width */ + else + host_cr &= ~MV_SDIO_HOST_CR_4BIT; /* 1-bit bus width */ + + /* Set high/normal speed mode. */ +#if 0 /* Some cards have problems with the highspeed-mode + * Not selecting High-Speed mode enables all cards to work + */ + + if ((ios->timing == bus_timing_hs ) && ( 1 == 0 ) ) + host_cr |= MV_SDIO_HOST_CR_HIGHSPEED; + else +#endif + host_cr &= ~MV_SDIO_HOST_CR_HIGHSPEED; + + MV_SDIO_WR4(sc, MV_SDIO_HOST_CR, host_cr); + + mtx_unlock(&sc->sc_mtx); + + return (0); +} + +static int +mv_sdio_request(device_t brdev, device_t reqdev, struct mmc_request *req) +{ + struct mv_sdio_softc *sc; + int rv; + + sc = device_get_softc(brdev); + rv = EBUSY; + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_req != NULL) { + mtx_unlock(&sc->sc_mtx); + return (rv); + } + + sc->sc_req = req; +/* + device_printf(sc->sc_dev, "cmd %d (hw state 0x%04x)\n", + req->cmd->opcode , MV_SDIO_RD4( sc, MV_SDIO_HOST_SR ) ); +*/ + rv = mv_sdio_start_command(sc, req->cmd); + + mtx_unlock(&sc->sc_mtx); + + return (rv); +} + +static int +mv_sdio_get_ro(device_t brdev, device_t reqdev) +{ + int rv; + + /* Check if card is read only. */ + rv = platform_sdio_slot_signal(MV_SDIO_SIG_WP); + + /* + * Assume that card is not write protected, when platform doesn't + * support WP signal. + */ + if (rv < 0) + rv = 0; + + return (rv); +} + +static int +mv_sdio_acquire_host(device_t brdev, device_t reqdev) +{ + struct mv_sdio_softc *sc; + int rv; + + sc = device_get_softc(brdev); + rv = 0; + + mtx_lock(&sc->sc_mtx); + while (sc->sc_bus_busy) + rv = mtx_sleep(sc, &sc->sc_mtx, PZERO, "sdioah", 0); + sc->sc_bus_busy++; + mtx_unlock(&sc->sc_mtx); + + return (rv); +} + +static int +mv_sdio_release_host(device_t brdev, device_t reqdev) +{ + struct mv_sdio_softc *sc; + + sc = device_get_softc(brdev); + + mtx_lock(&sc->sc_mtx); + sc->sc_bus_busy--; + wakeup(sc); + mtx_unlock(&sc->sc_mtx); + + return (0); +} + +static void +mv_sdio_finalize_request(struct mv_sdio_softc *sc) +{ + struct mmc_request *req; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + req = sc->sc_req; + + if (req) { + /* Finalize active request. */ + /*device_printf(sc->sc_dev, "Finalize request %i\n",req->cmd->opcode);*/ + sc->sc_req = NULL; + sc->sc_curcmd = NULL; + req->done(req); + + + } else + device_printf(sc->sc_dev, "No active request to finalize!\n"); +} + +static void +mv_sdio_init(device_t dev) +{ + struct mv_sdio_softc *sc; + uint32_t host_cr; + + sc = device_get_softc(dev); + + /* Disable interrupts. */ + sc->sc_irq_mask = 0; + sc->sc_eirq_mask = 0; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_EN, sc->sc_eirq_mask); + + /* Clear interrupt status registers. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, MV_SDIO_IRQ_ALL); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, MV_SDIO_EIRQ_ALL); + + /* Enable interrupt status registers. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR_EN, MV_SDIO_IRQ_ALL); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR_EN, MV_SDIO_EIRQ_ALL); + + /* Initialize Host Control Register. */ + host_cr = (MV_SDIO_HOST_CR_PUSHPULL | MV_SDIO_HOST_CR_BE | + MV_SDIO_HOST_CR_TMOVAL(MV_SDIO_TMO_MAX) | MV_SDIO_HOST_CR_TMO); + + MV_SDIO_WR4(sc, MV_SDIO_HOST_CR, host_cr); + + /* Stop clock and reset Transfer Mode Register. */ + MV_SDIO_WR4(sc, MV_SDIO_XFER, MV_SDIO_XFER_STOP_CLK); + + /* Set maximum clock divider value. */ + MV_SDIO_WR4(sc, MV_SDIO_CLK_DIV, MV_SDIO_CLK_DIV_MAX); + + /* Reset status, state machine and FIFOs synchronously. */ + MV_SDIO_WR4(sc, MV_SDIO_SW_RESET, MV_SDIO_SW_RESET_ALL); + DELAY(MV_SDIO_RESET_DELAY); +} + +static void +mv_sdio_init_host(struct mv_sdio_softc *sc) +{ + struct mmc_host *host; + + host = &sc->sc_host; + + /* Clear host structure. */ + bzero(host, sizeof(struct mmc_host)); + + /* Calculate minimum and maximum operating frequencies. */ + host->f_min = MV_SDIO_F_BASE / (MV_SDIO_CLK_DIV_MAX + 1); + host->f_max = MV_SDIO_F_MAX; + + /* Set operation conditions (voltage). */ + host->host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340; + + /* Set additional host controller capabilities. */ + host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_HSPEED; +} + +static void +mv_sdio_add_sysctls(struct mv_sdio_softc *sc) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *children; + struct sysctl_oid *tree; + + ctx = device_get_sysctl_ctx(sc->sc_dev); + children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)); + tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "params", + CTLFLAG_RD, 0, "Driver parameters"); + children = SYSCTL_CHILDREN(tree); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "use_dma", + CTLTYPE_UINT | CTLFLAG_RW, sc, 0, mv_sdio_sysctl_use_dma, + "I", "Use DMA for data transfers (0-1)"); +} + +/* + * This sysctl allows switching between DMA and PIO modes for data transfers: + * + * dev.mv_sdio..params.use_dma + * + * Values: + * + * - 1 sets DMA mode + * - 0 sets PIO mode + * + * Driver uses DMA mode by default. + */ +static int +mv_sdio_sysctl_use_dma(SYSCTL_HANDLER_ARGS) +{ + struct mv_sdio_softc *sc; + uint32_t use_dma; + int error; + + sc = (struct mv_sdio_softc *)arg1; + + use_dma = sc->sc_use_dma; + + error = sysctl_handle_int(oidp, &use_dma, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + + if (use_dma > 1) + return (EINVAL); + + mtx_lock(&sc->sc_mtx); + + /* Check if requested mode is already being used. */ + if (sc->sc_use_dma == use_dma) { + mtx_unlock(&sc->sc_mtx); + return (EPERM); + } + + if (!(sc->sc_mapped)) { + device_printf(sc->sc_dev, "DMA not initialized!\n"); + mtx_unlock(&sc->sc_mtx); + return (ENOMEM); + } + + /* Set new mode. */ + sc->sc_use_dma = use_dma; + + mtx_unlock(&sc->sc_mtx); + + return (0); +} + +static void +mv_sdio_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + + if (error != 0) + return; + + /* Get first segment's physical address. */ + *(bus_addr_t *)arg = segs->ds_addr; +} + +static int +mv_sdio_dma_init(struct mv_sdio_softc *sc) +{ + device_t dev; + bus_size_t dmabuf_size; + + dev = sc->sc_dev; + dmabuf_size = MAXPHYS; + + /* Create DMA tag. */ + if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ + MV_SDIO_DMA_SEGMENT_SIZE, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filtfunc, filtfuncarg */ + MAXPHYS, 1, /* maxsize, nsegments */ + MAXPHYS, BUS_DMA_ALLOCNOW, /* maxsegsz, flags */ + NULL, NULL, /* lockfunc, lockfuncarg */ + &sc->sc_dmatag) != 0) { + device_printf(dev, "Could not create DMA tag!\n"); + return (-1); + } + + /* Allocate DMA memory. */ + if (bus_dmamem_alloc(sc->sc_dmatag, (void **)&sc->sc_dmamem, + BUS_DMA_NOWAIT, &sc->sc_dmamap) != 0) { + device_printf(dev, "Could not allocate DMA memory!\n"); + mv_sdio_dma_finish(sc); + return (-1); + } + + /* Find the biggest available DMA buffer size. */ + while (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap, + (void *)sc->sc_dmamem, dmabuf_size, mv_sdio_getaddr, + &sc->sc_physaddr, 0) != 0) { + dmabuf_size >>= 1; + if (dmabuf_size < MV_SDIO_BLOCK_SIZE) { + device_printf(dev, "Could not load DMA map!\n"); + mv_sdio_dma_finish(sc); + return (-1); + } + } + + sc->sc_mapped++; + sc->sc_dma_size = dmabuf_size; + + return (0); +} + +static void +mv_sdio_dma_finish(struct mv_sdio_softc *sc) +{ + + /* Free DMA resources. */ + if (sc->sc_mapped) { + bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap); + sc->sc_mapped--; + } + if (sc->sc_dmamem != NULL) + bus_dmamem_free(sc->sc_dmatag, sc->sc_dmamem, sc->sc_dmamap); + if (sc->sc_dmamap != NULL) + bus_dmamap_destroy(sc->sc_dmatag, sc->sc_dmamap); + if (sc->sc_dmatag != NULL) + bus_dma_tag_destroy(sc->sc_dmatag); +} + +static int +mv_sdio_start_command(struct mv_sdio_softc *sc, struct mmc_command *cmd) +{ + struct mmc_request *req; + uint32_t cmdreg; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + req = sc->sc_req; + + sc->sc_curcmd = cmd; + + cmd->error = MMC_ERR_NONE; + + /* Check if card is in the slot. */ + if ((platform_sdio_slot_signal(MV_SDIO_SIG_CD) != -1) && + (sc->sc_card_present == 0)) { + cmd->error = MMC_ERR_FAILED; + mv_sdio_finalize_request(sc); + return (-1); + } + + /* Check if clock is enabled. */ + if (MV_SDIO_RD4(sc, MV_SDIO_XFER) & MV_SDIO_XFER_STOP_CLK) { + cmd->error = MMC_ERR_FAILED; + mv_sdio_finalize_request(sc); + return (-1); + } + + /* Write command argument. */ + MV_SDIO_WR4(sc, MV_SDIO_CMD_ARGL, cmd->arg & 0xffff); + MV_SDIO_WR4(sc, MV_SDIO_CMD_ARGH, cmd->arg >> 16); + + /* Determine response type. */ + if (cmd->flags & MMC_RSP_136) + cmdreg = MV_SDIO_CMD_RSP_136; + else if (cmd->flags & MMC_RSP_BUSY) + cmdreg = MV_SDIO_CMD_RSP_48_BUSY; + else if (cmd->flags & MMC_RSP_PRESENT) + cmdreg = MV_SDIO_CMD_RSP_48; + else { + /* No response. */ + cmdreg = MV_SDIO_CMD_RSP_NONE; + /* Enable host to detect unexpected response. */ + cmdreg |= MV_SDIO_CMD_UNEXPECTED_RSP; + sc->sc_irq_mask |= MV_SDIO_CMD_UNEXPECTED_RSP; + } + + /* Check command checksum if needed. */ + if (cmd->flags & MMC_RSP_CRC) + cmdreg |= MV_SDIO_CMD_CRC7; + /* Check command opcode if needed. */ + if (cmd->flags & MMC_RSP_OPCODE) + cmdreg |= MV_SDIO_CMD_INDEX_CHECK; + + /* Set commannd opcode. */ + cmdreg |= MV_SDIO_CMD_INDEX(cmd->opcode); + + /* Setup interrupts. */ + sc->sc_irq_mask = MV_SDIO_IRQ_CMD; + sc->sc_eirq_mask = MV_SDIO_EIRQ_ALL; + + /* Prepare data transfer. */ + if (cmd->data) { + cmdreg |= (MV_SDIO_CMD_DATA_PRESENT | MV_SDIO_CMD_DATA_CRC16); + if (mv_sdio_start_data(sc, cmd->data) < 0) { + cmd->error = MMC_ERR_FAILED; + printf("mv_sdio_start_data() failed!\n"); + mv_sdio_finalize_request(sc); + return (-1); + } + } + + /* Write command register. */ + MV_SDIO_WR4(sc, MV_SDIO_CMD, cmdreg); + + /* Clear interrupt status. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, ~MV_SDIO_IRQ_CARD_EVENT /*MV_SDIO_IRQ_ALL*/); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, 0xffff /*MV_SDIO_EIRQ_ALL*/); + + /* Update interrupt/error interrupt enable registers. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_EN, sc->sc_eirq_mask); + + /* Do not complete request, interrupt handler will do this. */ + return (0); +} + +static void +mv_sdio_finish_command(struct mv_sdio_softc *sc) +{ + struct mmc_command *cmd; + struct mmc_data *data; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + cmd = sc->sc_curcmd; + data = cmd->data; + + /* Get response. */ + if (cmd->flags & MMC_RSP_PRESENT) { + if(cmd->flags & MMC_RSP_136) + /* 136-bit response. */ + mv_sdio_handle_136bit_resp(sc); + else + /* 48-bit response. */ + mv_sdio_handle_48bit_resp(sc, NULL); + } + + if (data) { + /* + * Disable command complete interrupt. It has already been + * handled. + */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_CMD; + + /* Enable XFER interrupt. */ + sc->sc_irq_mask |= MV_SDIO_IRQ_XFER; + + /* Check which data interrupts we need to activate. */ + if (sc->sc_use_dma) + /* DMA transaction. */ + sc->sc_irq_mask |= MV_SDIO_IRQ_DMA; + else if (data->flags & MMC_DATA_READ) + /* Read transaction in PIO mode. */ + sc->sc_irq_mask |= MV_SDIO_IRQ_RX_FULL; + else + /* Write transaction in PIO mode. */ + sc->sc_irq_mask |= MV_SDIO_IRQ_TX_EMPTY; + + /* Check if Auto-CMD12 interrupt will be needed. */ + if (sc->sc_req->stop) + sc->sc_irq_mask |= MV_SDIO_IRQ_AUTOCMD12; + + /* Update interrupt enable register. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } else { + /* We're done. Disable interrupts and finalize request. */ + mv_sdio_disable_intr(sc); + mv_sdio_finalize_request(sc); + } +} + +static int +mv_sdio_start_data(struct mv_sdio_softc *sc, struct mmc_data *data) +{ + struct mmc_command *stop; + uint32_t autocmd12reg, xfer, host_sr; + size_t blk_size, blk_count; + int retries; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + /* + * No transfer can be started when FIFO_EMPTY bit in MV_SDIO_HOST_SR + * is not set. This bit is sometimes not set instantly after XFER + * interrupt has been asserted. + */ + host_sr = MV_SDIO_RD4(sc, MV_SDIO_HOST_SR); + + retries = 10; + while (!(host_sr & MV_SDIO_HOST_SR_FIFO_EMPTY)) { + if (retries == 0) + return (-1); + retries--; + DELAY(MV_SDIO_FIFO_EMPTY_DELAY); + host_sr = MV_SDIO_RD4(sc, MV_SDIO_HOST_SR); + } + + /* Clear data offset. */ + sc->sc_data_offset = 0; + + /* + * Set block size. It can be less than or equal to MV_SDIO_BLOCK_SIZE + * bytes. + */ + blk_size = (data->len < MV_SDIO_BLOCK_SIZE) ? data->len : + MV_SDIO_BLOCK_SIZE; + MV_SDIO_WR4(sc, MV_SDIO_BLK_SIZE, blk_size); + + /* Set block count. */ + blk_count = (data->len + MV_SDIO_BLOCK_SIZE - 1) / MV_SDIO_BLOCK_SIZE; + MV_SDIO_WR4(sc, MV_SDIO_BLK_COUNT, blk_count); + + /* We want to initiate transfer by software. */ + xfer = MV_SDIO_XFER_SW_WR_EN; + + if (sc->sc_use_dma) { + /* Synchronize before DMA transfer. */ + if (data->flags & MMC_DATA_READ) + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, + BUS_DMASYNC_PREREAD); + else { + memcpy(sc->sc_dmamem, data->data, data->len); + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, + BUS_DMASYNC_PREWRITE); + } + + /* Write DMA buffer address register. */ + MV_SDIO_WR4(sc, MV_SDIO_DMA_ADDRL, sc->sc_physaddr & 0xffff); + MV_SDIO_WR4(sc, MV_SDIO_DMA_ADDRH, sc->sc_physaddr >> 16); + } else + /* Set PIO transfer mode. */ + xfer |= MV_SDIO_XFER_PIO; + + /* + * Prepare Auto-CMD12. This command is automatically sent to the card + * by the host controller to stop multiple-block data transaction. + */ + if (sc->sc_req->stop) { + stop = sc->sc_req->stop; + + /* Set Auto-CMD12 argument. */ + MV_SDIO_WR4(sc, MV_SDIO_AUTOCMD12_ARGL, stop->arg & 0xffff); + MV_SDIO_WR4(sc, MV_SDIO_AUTOCMD12_ARGH, stop->arg >> 16); + + /* Set Auto-CMD12 opcode. */ + autocmd12reg = MV_SDIO_AUTOCMD12_INDEX(stop->opcode); + + /* Check busy signal if needed. */ + if (stop->flags & MMC_RSP_BUSY) + autocmd12reg |= MV_SDIO_AUTOCMD12_BUSY_CHECK; + /* Check Auto-CMD12 index. */ + if (stop->flags & MMC_RSP_OPCODE) + autocmd12reg |= MV_SDIO_AUTOCMD12_INDEX_CHECK; + + MV_SDIO_WR4(sc, MV_SDIO_AUTOCMD12, autocmd12reg); + + xfer |= MV_SDIO_XFER_AUTOCMD12; + } + + /* Change data direction. */ + if (data->flags & MMC_DATA_READ) + xfer |= MV_SDIO_XFER_TO_HOST; + + /* Write transfer mode register. */ + MV_SDIO_WR4(sc, MV_SDIO_XFER, xfer); + + return (0); +} + +static void +mv_sdio_handle_136bit_resp(struct mv_sdio_softc *sc) +{ + struct mmc_command *cmd; + uint32_t resp[8]; + uint32_t base, extra; + int i, j, off; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + cmd = sc->sc_curcmd; + + /* Collect raw response from the controller. */ + for (i = 0; i < 8; i++) + resp[i] = MV_SDIO_RD4(sc, MV_SDIO_RSP(i)); + + /* Response passed to MMC bus is shifted by one byte. */ + extra = 0; + for (i = 0, j = 7; i < 4; i++, j -= 2) { + off = (i ? 0 : 2); + base = resp[j] | (resp[j - 1] << (16 - off)); + cmd->resp[3 - i] = (base << (6 + off)) + extra; + extra = base >> (26 - off); + } +} + +static void +mv_sdio_handle_48bit_resp(struct mv_sdio_softc *sc, struct mmc_command *stop) +{ + struct mmc_command *cmd; + uint32_t resp[3], word; + uint8_t *rp; + int i; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (stop == NULL) + cmd = sc->sc_curcmd; + else + cmd = stop; + + /* Collect raw response from the controller. */ + for (i = 0; i < 3; i++) { + if (stop == NULL) + resp[i] = MV_SDIO_RD4(sc, MV_SDIO_RSP(i)); + else + resp[i] = MV_SDIO_RD4(sc, MV_SDIO_AUTOCMD12_RSP(i)); + } + + /* Clear MMC bus response buffer. */ + bzero(&cmd->resp[0], 4 * sizeof(uint32_t)); + + /* + * Fill MMC bus response buffer. + */ + + rp = (uint8_t *)&cmd->resp[0]; + + /* Response bits [45:14] */ + word = (resp[1] & MV_SDIO_RSP48_BM16) | + ((resp[0] & MV_SDIO_RSP48_BM16) << 16); + + /* Response bits [15:14] and [13:8] */ + *rp++ = (resp[2] & MV_SDIO_RSP48_BM6) | + ((word & MV_SDIO_RSP48_BM2) << 6); + + /* Response bits [15:14] are already included. */ + word >>= 2; + + /* Response bits [45:16] */ + memcpy(rp, &word, sizeof(uint32_t)); +} + +static void +mv_sdio_intr(void *arg) +{ + struct mv_sdio_softc *sc; + uint32_t irq_stat, eirq_stat; + + sc = (struct mv_sdio_softc *)arg; +#if 0 + device_printf(sc->sc_dev,"intr 0x%04x intr_en 0x%04x hw_state 0x%04x\n", + MV_SDIO_RD4( sc, MV_SDIO_IRQ_SR ) , + MV_SDIO_RD4( sc, MV_SDIO_IRQ_EN ), + MV_SDIO_RD4( sc, MV_SDIO_HOST_SR )); +#endif + + + mtx_lock(&sc->sc_mtx); + + + + irq_stat = MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & sc->sc_irq_mask; + eirq_stat = MV_SDIO_RD4(sc, MV_SDIO_EIRQ_SR) & sc->sc_eirq_mask; + + /* + * In case of error interrupt, interrupt cause will be identified by + * checking bits in error interrupt status register. + */ + irq_stat &= ~MV_SDIO_IRQ_ERR; + + /* Handle command interrupts. */ + if ((irq_stat & MV_SDIO_IRQS_CMD) || + (eirq_stat & MV_SDIO_EIRQS_CMD)) { + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, irq_stat); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, eirq_stat); + mv_sdio_cmd_intr(sc, irq_stat, eirq_stat); + irq_stat &= ~MV_SDIO_IRQS_CMD; + eirq_stat &= ~MV_SDIO_EIRQS_CMD; + } + + /* Handle data interrupts. */ + if ((irq_stat & MV_SDIO_IRQS_DATA) || + (eirq_stat & MV_SDIO_EIRQS_DATA)) { + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, irq_stat); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, eirq_stat); + mv_sdio_data_intr(sc, irq_stat, eirq_stat); + irq_stat &= ~MV_SDIO_IRQS_DATA; + eirq_stat &= ~MV_SDIO_EIRQS_DATA; + } + + /* Handle unexpected interrupts. */ + if (irq_stat) { + device_printf(sc->sc_dev, "Unexpected interrupt(s)! " + "IRQ SR = 0x%08x\n", irq_stat); + /* Clear interrupt status. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, irq_stat); + } + if (eirq_stat) { + device_printf(sc->sc_dev, "Unexpected error interrupt(s)! " + "EIRQ SR = 0x%08x\n", eirq_stat); + /* Clear error interrupt status. */ + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, eirq_stat); + } + + mtx_unlock(&sc->sc_mtx); +} + +static void +mv_sdio_cmd_intr(struct mv_sdio_softc *sc, uint32_t irq, uint32_t eirq) +{ + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (!sc->sc_curcmd) { + device_printf(sc->sc_dev, "Got command interrupt, but there " + "is no active command!\n"); + return; + } + + /* Handle unexpected response error. */ + if (irq & MV_SDIO_IRQ_UNEXPECTED_RSP) { + sc->sc_curcmd->error = MMC_ERR_FAILED; + device_printf(sc->sc_dev, "Unexpected response!\n"); + } + + /* Handle errors. */ + if (eirq & MV_SDIO_EIRQ_CMD_TMO) { + sc->sc_curcmd->error = MMC_ERR_TIMEOUT; + device_printf(sc->sc_dev, "Error - command %d timeout!\n", + sc->sc_curcmd->opcode); + } else if (eirq & MV_SDIO_EIRQ_CMD_CRC7) { + sc->sc_curcmd->error = MMC_ERR_BADCRC; + device_printf(sc->sc_dev, "Error - bad command %d " + "checksum!\n", sc->sc_curcmd->opcode); + } else if (eirq) { + sc->sc_curcmd->error = MMC_ERR_FAILED; + device_printf(sc->sc_dev, "Command %d error!\n", + sc->sc_curcmd->opcode); + } + + if (sc->sc_curcmd->error != MMC_ERR_NONE) { + /* Error. Disable interrupts and finalize request. */ + mv_sdio_disable_intr(sc); + mv_sdio_finalize_request(sc); + return; + } + + if (irq & MV_SDIO_IRQ_CMD) + mv_sdio_finish_command(sc); +} + +static void +mv_sdio_data_intr(struct mv_sdio_softc *sc, uint32_t irq, uint32_t eirq) +{ + struct mmc_command *stop; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (!sc->sc_curcmd) { + device_printf(sc->sc_dev, "Got data interrupt, but there is " + "no active command.\n"); + return; + } + if ((!sc->sc_curcmd->data) && ((sc->sc_curcmd->flags & + MMC_RSP_BUSY) == 0)) { + device_printf(sc->sc_dev, "Got data interrupt, but there is " + "no active data transaction.n\n"); + sc->sc_curcmd->error = MMC_ERR_FAILED; + return; + } + + /* Handle errors. */ + if(eirq & MV_SDIO_EIRQ_DATA_TMO) { + sc->sc_curcmd->error = MMC_ERR_TIMEOUT; + device_printf(sc->sc_dev, "Data %s timeout!\n", + (sc->sc_curcmd->data->flags & MMC_DATA_READ) ? "read" : + "write"); + } else if (eirq & (MV_SDIO_EIRQ_DATA_CRC16 | + MV_SDIO_EIRQ_DATA_ENDBIT)) { + sc->sc_curcmd->error = MMC_ERR_BADCRC; + device_printf(sc->sc_dev, "Bad data checksum!\n"); + } else if (eirq) { + sc->sc_curcmd->error = MMC_ERR_FAILED; + device_printf(sc->sc_dev, "Data error!: 0x%04X \n", + eirq); + + if( 0 != ( eirq & MV_SDIO_EIRQ_CRC_STAT ) ) + { + device_printf(sc->sc_dev, "MV_SDIO_EIRQ_CRC_STAT\n"); + } + } + + /* Handle Auto-CMD12 error. */ + if (eirq & MV_SDIO_EIRQ_AUTOCMD12) { + sc->sc_req->stop->error = MMC_ERR_FAILED; + sc->sc_curcmd->error = MMC_ERR_FAILED; + device_printf(sc->sc_dev, "Auto-CMD12 error!\n"); + } + + if (sc->sc_curcmd->error != MMC_ERR_NONE) { + /* Error. Disable interrupts and finalize request. */ + mv_sdio_disable_intr(sc); + mv_sdio_finalize_request(sc); + return; + } + + /* Handle PIO interrupt. */ + if (irq & (MV_SDIO_IRQ_TX_EMPTY | MV_SDIO_IRQ_RX_FULL)) + mv_sdio_transfer_pio(sc); + + /* Handle DMA interrupt. */ + if (irq & (MV_SDIO_IRQ_DMA)) { + /* Synchronize DMA buffer. */ + if (MV_SDIO_RD4(sc, MV_SDIO_XFER) & MV_SDIO_XFER_TO_HOST) { + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, + BUS_DMASYNC_POSTWRITE); + memcpy(sc->sc_curcmd->data->data, sc->sc_dmamem, + sc->sc_curcmd->data->len); + } else + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, + BUS_DMASYNC_POSTREAD); + + /* Disable DMA interrupt. */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_DMA; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } + + /* Handle Auto-CMD12 interrupt. */ + if (irq & (MV_SDIO_IRQ_AUTOCMD12)) { + stop = sc->sc_req->stop; + /* Get 48-bit response. */ + mv_sdio_handle_48bit_resp(sc, stop); + + /* Disable Auto-CMD12 interrupt. */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_AUTOCMD12; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } + + /* Transfer finished. Disable interrupts and finalize request. */ + if (irq & (MV_SDIO_IRQ_XFER)) { + mv_sdio_disable_intr(sc); + mv_sdio_finalize_request(sc); + } +} + +static void +mv_sdio_disable_intr(struct mv_sdio_softc *sc) +{ + + /* Disable interrupts that were enabled. */ + sc->sc_irq_mask &= ~(sc->sc_irq_mask); + sc->sc_eirq_mask &= ~(sc->sc_eirq_mask); + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_EN, sc->sc_eirq_mask); +} + +static void +mv_sdio_card_task(void *arg, int pending) +{ + struct mv_sdio_softc *sc; + + int device_probe_and_attach_ret_val = 0; + + sc = (struct mv_sdio_softc *)arg; + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_card_present) { + if (sc->sc_child) { + mtx_unlock(&sc->sc_mtx); + return; + } + + /* Initialize host controller's registers. */ + mv_sdio_init(sc->sc_dev); + + sc->sc_child = device_add_child(sc->sc_dev, "mmc", -1); + if (sc->sc_child == NULL) { + device_printf(sc->sc_dev, "Could not add MMC bus!\n"); + mtx_unlock(&sc->sc_mtx); + return; + } + + /* Initialize host structure for MMC bus. */ + mv_sdio_init_host(sc); + + device_set_ivars(sc->sc_child, &sc->sc_host); + + mtx_unlock(&sc->sc_mtx); + + device_probe_and_attach_ret_val = device_probe_and_attach(sc->sc_child); + + if( 0 != device_probe_and_attach_ret_val ) { + device_printf(sc->sc_dev, "MMC bus failed on probe " + "and attach! %i\n",device_probe_and_attach_ret_val); + device_delete_child(sc->sc_dev, sc->sc_child); + sc->sc_child = NULL; + } + } else { + if (sc->sc_child == NULL) { + mtx_unlock(&sc->sc_mtx); + return; + } + + mtx_unlock(&sc->sc_mtx); + if (device_delete_child(sc->sc_dev, sc->sc_child) != 0) { + device_printf(sc->sc_dev, "Could not delete MMC " + "bus!\n"); + } + sc->sc_child = NULL; + } +} + +static uint32_t +mv_sdio_read_fifo(struct mv_sdio_softc *sc) +{ + uint32_t data; + device_printf(sc->sc_dev, "This is not tested, yet MV_SDIO_FIFO not ensured\n "); + + while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_RX_FULL)); + data = MV_SDIO_RD4(sc, MV_SDIO_FIFO); + while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_RX_FULL)); + data |= (MV_SDIO_RD4(sc, MV_SDIO_FIFO) << 16); + return data; +} + +static void +mv_sdio_write_fifo(struct mv_sdio_softc *sc, uint32_t val) +{ + while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_TX_EMPTY)); + MV_SDIO_WR4(sc, MV_SDIO_FIFO, val & 0xffff); + while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_TX_EMPTY)); + MV_SDIO_WR4(sc, MV_SDIO_FIFO, val >> 16); +} + +static void +mv_sdio_transfer_pio(struct mv_sdio_softc *sc) +{ + struct mmc_command *cmd; + + cmd = sc->sc_curcmd; + + if (cmd->data->flags & MMC_DATA_READ) { + while (MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & + MV_SDIO_IRQ_RX_FULL) { + mv_sdio_read_block_pio(sc); + /* + * Assert delay after each block transfer to meet read + * access timing constraint. + */ + DELAY(MV_SDIO_RD_DELAY); + if (sc->sc_data_offset >= cmd->data->len) + break; + } + /* All blocks read in PIO mode. Disable interrupt. */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_RX_FULL; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } else { + while (MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & + MV_SDIO_IRQ_TX_EMPTY) { + mv_sdio_write_block_pio(sc); + /* Wait while card is programming the memory. */ + while ((MV_SDIO_RD4(sc, MV_SDIO_HOST_SR) & + MV_SDIO_HOST_SR_CARD_BUSY)); + /* + * Assert delay after each block transfer to meet + * write access timing constraint. + */ + DELAY(MV_SDIO_WR_DELAY); + + if (sc->sc_data_offset >= cmd->data->len) + break; + } + /* All blocks written in PIO mode. Disable interrupt. */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_TX_EMPTY; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } +} + +static void +mv_sdio_read_block_pio(struct mv_sdio_softc *sc) +{ + uint32_t data; + char *buffer; + size_t left; + + buffer = sc->sc_curcmd->data->data; + buffer += sc->sc_data_offset; + /* Transfer one block at a time. */ + left = min(MV_SDIO_BLOCK_SIZE, sc->sc_curcmd->data->len - + sc->sc_data_offset); + sc->sc_data_offset += left; + + /* Handle unaligned and aligned buffer cases. */ + if ((intptr_t)buffer & 3) { + while (left > 3) { + data = mv_sdio_read_fifo(sc); + buffer[0] = data; + buffer[1] = (data >> 8); + buffer[2] = (data >> 16); + buffer[3] = (data >> 24); + buffer += 4; + left -= 4; + } + } else { + while (left > 3) { + data = mv_sdio_read_fifo(sc); + *((uint32_t *)buffer) = data; + buffer += 4; + left -= 4; + } + } + /* Handle uneven size case. */ + if (left > 0) { + data = mv_sdio_read_fifo(sc); + while (left > 0) { + *(buffer++) = data; + data >>= 8; + left--; + } + } +} + +static void +mv_sdio_write_block_pio(struct mv_sdio_softc *sc) +{ + uint32_t data = 0; + char *buffer; + size_t left; + + buffer = sc->sc_curcmd->data->data; + buffer += sc->sc_data_offset; + /* Transfer one block at a time. */ + left = min(MV_SDIO_BLOCK_SIZE, sc->sc_curcmd->data->len - + sc->sc_data_offset); + sc->sc_data_offset += left; + + /* Handle unaligned and aligned buffer cases. */ + if ((intptr_t)buffer & 3) { + while (left > 3) { + data = buffer[0] + + (buffer[1] << 8) + + (buffer[2] << 16) + + (buffer[3] << 24); + left -= 4; + buffer += 4; + mv_sdio_write_fifo(sc, data); + } + } else { + while (left > 3) { + data = *((uint32_t *)buffer); + left -= 4; + buffer += 4; + mv_sdio_write_fifo(sc, data); + } + } + /* Handle uneven size case. */ + if (left > 0) { + data = 0; + while (left > 0) { + data <<= 8; + data += *(buffer++); + left--; + } + mv_sdio_write_fifo(sc, data); + } +} + +static int +mv_sdio_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) +{ + struct mv_sdio_softc *sc; + struct mmc_host *host; + + sc = device_get_softc(dev); + host = device_get_ivars(child); + + switch (index) { + case MMCBR_IVAR_BUS_MODE: + *(int *)result = host->ios.bus_mode; + break; + case MMCBR_IVAR_BUS_WIDTH: + *(int *)result = host->ios.bus_width; + break; + case MMCBR_IVAR_CHIP_SELECT: + *(int *)result = host->ios.chip_select; + break; + case MMCBR_IVAR_CLOCK: + *(int *)result = host->ios.clock; + break; + case MMCBR_IVAR_F_MIN: + *(int *)result = host->f_min; + break; + case MMCBR_IVAR_F_MAX: + *(int *)result = host->f_max; + break; + case MMCBR_IVAR_HOST_OCR: + *(int *)result = host->host_ocr; + break; + case MMCBR_IVAR_MODE: + *(int *)result = host->mode; + break; + case MMCBR_IVAR_OCR: + *(int *)result = host->ocr; + break; + case MMCBR_IVAR_POWER_MODE: + *(int *)result = host->ios.power_mode; + break; + case MMCBR_IVAR_VDD: + *(int *)result = host->ios.vdd; + break; + case MMCBR_IVAR_CAPS: + *(int *)result = host->caps; + break; + case MMCBR_IVAR_TIMING: + *(int *)result = host->ios.timing; + break; + case MMCBR_IVAR_MAX_DATA: + mtx_lock(&sc->sc_mtx); + /* Return maximum number of blocks the driver can handle. */ + if (sc->sc_use_dma) + *(int *)result = (sc->sc_dma_size / + MV_SDIO_BLOCK_SIZE); + else + *(int *)result = MV_SDIO_BLOCKS_MAX; + mtx_unlock(&sc->sc_mtx); + break; + default: + return (EINVAL); + } + + return (0); +} + +static int +mv_sdio_write_ivar(device_t dev, device_t child, int index, uintptr_t value) +{ + struct mmc_host *host; + + host = device_get_ivars(child); + + switch (index) { + case MMCBR_IVAR_BUS_MODE: + host->ios.bus_mode = value; + break; + case MMCBR_IVAR_BUS_WIDTH: + host->ios.bus_width = value; + break; + case MMCBR_IVAR_CHIP_SELECT: + host->ios.chip_select = value; + break; + case MMCBR_IVAR_CLOCK: + host->ios.clock = value; + break; + case MMCBR_IVAR_MODE: + host->mode = value; + break; + case MMCBR_IVAR_OCR: + host->ocr = value; + break; + case MMCBR_IVAR_POWER_MODE: + host->ios.power_mode = value; + break; + case MMCBR_IVAR_VDD: + host->ios.vdd = value; + break; + case MMCBR_IVAR_TIMING: + host->ios.timing = value; + break; + case MMCBR_IVAR_CAPS: + case MMCBR_IVAR_HOST_OCR: + case MMCBR_IVAR_F_MIN: + case MMCBR_IVAR_F_MAX: + case MMCBR_IVAR_MAX_DATA: + default: + /* Instance variable not writable. */ + return (EINVAL); + } + + return (0); +} + diff --git a/sys/arm/mv/mv_sdio.h b/sys/arm/mv/mv_sdio.h new file mode 100644 index 0000000..b54b59d --- /dev/null +++ b/sys/arm/mv/mv_sdio.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2008 Marvell Semiconductors, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _MVSDMMC_INCLUDE +#define _MVSDMMC_INCLUDE + + +#define MVSDMMC_DMA_SIZE 65536 + + + +/* + * The base MMC clock rate + */ + +#define MVSDMMC_CLOCKRATE_MIN 100000 +#define MVSDMMC_CLOCKRATE_MAX 50000000 + +#define MVSDMMC_BASE_FAST_CLOCK 200000000 + + +/* + * SDIO register + */ + +#define MV_SDIO_DMA_ADDRL 0x000 +#define MV_SDIO_DMA_ADDRH 0x004 +#define MV_SDIO_BLK_SIZE 0x008 +#define MV_SDIO_BLK_COUNT 0x00c +#define MV_SDIO_CMD 0x01c +#define MV_SDIO_CMD_ARGL 0x010 +#define MV_SDIO_CMD_ARGH 0x014 +#define MV_SDIO_XFER 0x018 +#define MV_SDIO_HOST_SR 0x048 +#define MV_SDIO_HOST_CR 0x050 +#define MV_SDIO_SW_RESET 0x05c +#define MV_SDIO_IRQ_SR 0x060 +#define MV_SDIO_EIRQ_SR 0x064 +#define MV_SDIO_IRQ_SR_EN 0x068 +#define MV_SDIO_EIRQ_SR_EN 0x06c +#define MV_SDIO_IRQ_EN 0x070 +#define MV_SDIO_EIRQ_EN 0x074 +#define MV_SDIO_AUTOCMD12_ARGL 0x084 +#define MV_SDIO_AUTOCMD12_ARGH 0x088 +#define MV_SDIO_AUTOCMD12 0x08c +#define MV_SDIO_CLK_DIV 0x128 +#define MV_SDIO_FIFO 0xa2100 /* FIXME!!! */ + +#define MV_SDIO_RSP(i) (0x020 + ((i)<<2)) +#define MV_SDIO_AUTOCMD12_RSP(i) (0x090 + ((i)<<2)) + +/* + * SDIO Status-Register + */ +#define MV_SDIO_HOST_SR_CARD_BUSY (1<<1) +#define MV_SDIO_HOST_SR_FIFO_EMPTY (1<<13) + + + +/* + * SDIO_CMD + */ +#define MV_SDIO_CMD_RSP_NONE (0 << 0) +#define MV_SDIO_CMD_RSP_136 (1 << 0) +#define MV_SDIO_CMD_RSP_48 (2 << 0) +#define MV_SDIO_CMD_RSP_48_BUSY (3 << 0) +#define MV_SDIO_CMD_DATA_CRC16 (1<<2) +#define MV_SDIO_CMD_CRC7 (1<<3) +#define MV_SDIO_CMD_INDEX_CHECK (1<<4) +#define MV_SDIO_CMD_DATA_PRESENT (1<<5) +#define MV_SDIO_CMD_UNEXPECTED_RSP (1<<7) +#define MV_SDIO_CMD_INDEX(x) ( (x) << 8 ) + + +/* + * SDIO_XFER_MODE + */ +#define MV_SDIO_XFER_STOP_CLK (1 << 5) +#define MV_SDIO_XFER_TO_HOST (1 << 4) +#define MV_SDIO_XFER_PIO (1 << 3) +#define MV_SDIO_XFER_AUTOCMD12 (1 << 2) +#define MV_SDIO_XFER_SW_WR_EN (1 << 1) + +/* + * SDIO_HOST_CTRL + */ +#define MV_SDIO_HOST_CR_PUSHPULL (1 << 0) +#define MV_SDIO_HOST_CR_MMC (3 << 1) +#define MV_SDIO_HOST_CR_BE (1 << 3) +#define MV_SDIO_HOST_CR_4BIT (1 << 9) +#define MV_SDIO_HOST_CR_HIGHSPEED (1 << 10) + +#define MV_SDIO_HOST_CR_TMOVAL(x) ((x) << 11) +#define MV_SDIO_HOST_CR_TMO ( 1 << 15 ) + +/* + * NORmal status bits + */ + + +#define MV_SDIO_IRQ_ERR (1<<15) +#define MV_SDIO_IRQ_UNEXPECTED_RSP (1<<14) +#define MV_SDIO_IRQ_AUTOCMD12 (1<<13) +#define MV_SDIO_IRQ_SUSPENSE_ON_IRQ_EN (1<<12) +#define MV_SDIO_IRQ_IMB_FIFO_WORD_AVAIL (1<<11) +#define MV_SDIO_IRQ_IMB_FIFO_WORD_FILLED (1<<10) +#define MV_SDIO_IRQ_READ_WAIT (1<<9) +#define MV_SDIO_IRQ_CARD_EVENT (1<<8) +#define MV_SDIO_IRQ_RX_FULL (1<<5) +#define MV_SDIO_IRQ_TX_EMPTY (1<<4) +#define MV_SDIO_IRQ_DMA (1<<3) +#define MV_SDIO_IRQ_BLOCK_GAP (1<<2) +#define MV_SDIO_IRQ_XFER (1<<1) +#define MV_SDIO_IRQ_CMD (1<<0) + +#define MV_SDIO_IRQ_ALL (MV_SDIO_IRQ_CMD | MV_SDIO_IRQ_XFER | MV_SDIO_IRQ_BLOCK_GAP | MV_SDIO_IRQ_DMA | MV_SDIO_IRQ_RX_FULL | MV_SDIO_IRQ_TX_EMPTY | MV_SDIO_IRQ_CARD_EVENT | MV_SDIO_IRQ_READ_WAIT | MV_SDIO_IRQ_IMB_FIFO_WORD_FILLED | MV_SDIO_IRQ_IMB_FIFO_WORD_AVAIL | MV_SDIO_IRQ_SUSPENSE_ON_IRQ_EN | MV_SDIO_IRQ_AUTOCMD12 | MV_SDIO_IRQ_UNEXPECTED_RSP | MV_SDIO_IRQ_ERR ) + +//#define MV_SDIO_IRQ_SR + + +/* + * ERR status bits + */ +#define MV_SDIO_EIRQ_CRC_STAT (1<<14) +#define MV_SDIO_EIRQ_CRC_STARTBIT (1<<13) +#define MV_SDIO_EIRQ_CRC_ENDBIT (1<<12) +#define MV_SDIO_EIRQ_RSP_TBIT (1<<11) +#define MV_SDIO_EIRQ_XFER_SIZE (1<<10) +#define MV_SDIO_EIRQ_CMD_STARTBIT (1<<9) +#define MV_SDIO_EIRQ_AUTOCMD12 (1<<8) +#define MV_SDIO_EIRQ_DATA_ENDBIT (1<<6) +#define MV_SDIO_EIRQ_DATA_CRC16 (1<<5) +#define MV_SDIO_EIRQ_DATA_TMO (1<<4) +#define MV_SDIO_EIRQ_CMD_INDEX (1<<3) +#define MV_SDIO_EIRQ_CMD_ENDBIT (1<<2) +#define MV_SDIO_EIRQ_CMD_CRC7 (1<<1) +#define MV_SDIO_EIRQ_CMD_TMO (1<<0) + +#define MV_SDIO_EIRQ_ALL (MV_SDIO_EIRQ_CMD_TMO | \ + MV_SDIO_EIRQ_CMD_CRC7 | \ + MV_SDIO_EIRQ_CMD_ENDBIT | \ + MV_SDIO_EIRQ_CMD_INDEX | \ + MV_SDIO_EIRQ_DATA_TMO | \ + MV_SDIO_EIRQ_DATA_CRC16 | \ + MV_SDIO_EIRQ_DATA_ENDBIT | \ + MV_SDIO_EIRQ_AUTOCMD12 | \ + MV_SDIO_EIRQ_CMD_STARTBIT |\ + MV_SDIO_EIRQ_XFER_SIZE |\ + MV_SDIO_EIRQ_RSP_TBIT |\ + MV_SDIO_EIRQ_CRC_ENDBIT |\ + MV_SDIO_EIRQ_CRC_STARTBIT |\ + MV_SDIO_EIRQ_CRC_STAT) + +/* AUTOCMD12 register values */ +#define MV_SDIO_AUTOCMD12_BUSY_CHECK (1<<0) +#define MV_SDIO_AUTOCMD12_INDEX_CHECK (1<<1) +#define MV_SDIO_AUTOCMD12_INDEX(x) (x<<8) + +/* Software reset register */ +#define MV_SDIO_SW_RESET_ALL (1<<8) + +/* */ +#define MV_SDIO_SIG_CD 1 +#define MV_SDIO_SIG_WP 2 + +#endif /* _MVSDMMC_INCLUDE */ + diff --git a/sys/boot/uboot/common/main.c b/sys/boot/uboot/common/main.c index 82c86b2..0a5b368 100644 --- a/sys/boot/uboot/common/main.c +++ b/sys/boot/uboot/common/main.c @@ -122,6 +122,7 @@ main(void) struct api_signature *sig = NULL; int i; struct open_file f; + char *ub_currdev; if (!api_search_sig(&sig)) return (-1); @@ -166,6 +167,7 @@ main(void) printf("(%s, %s)\n", bootprog_maker, bootprog_date); meminfo(); + ub_currdev = ub_env_get("currdev"); /* * March through the device switch probing for things. */ @@ -198,8 +200,13 @@ main(void) if (devsw[i] == NULL) panic("No boot device found!"); - env_setenv("currdev", EV_VOLATILE, uboot_fmtdev(&currdev), - uboot_setcurrdev, env_nounset); + if (ub_currdev) { + env_setenv("currdev", EV_VOLATILE, ub_currdev, + uboot_setcurrdev, env_nounset); + } else { + env_setenv("currdev", EV_VOLATILE, uboot_fmtdev(&currdev), + uboot_setcurrdev, env_nounset); + } env_setenv("loaddev", EV_VOLATILE, uboot_fmtdev(&currdev), env_noset, env_nounset); diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c index f101e65..5016828 100644 --- a/sys/dev/mmc/mmc.c +++ b/sys/dev/mmc/mmc.c @@ -67,15 +67,32 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include + #include "mmcbr_if.h" #include "mmcbus_if.h" +/* CIS structure of SDIO card */ +struct sdio_function { + int number; + uint8_t cis1_major; + uint8_t cis1_minor; + uint16_t manufacturer; + uint16_t product; + uint16_t fn0_blksize; + uint8_t max_tran_speed; + STAILQ_ENTRY(sdio_function) sdiof_list; +}; + struct mmc_softc { device_t dev; struct mtx sc_mtx; struct intr_config_hook config_intrhook; device_t owner; uint32_t last_rca; + uint8_t sdio_nfunc; + struct sdio_function sdio_func0; + STAILQ_HEAD(, sdio_function) sdiof_head; }; /* @@ -96,11 +113,13 @@ struct mmc_ivars { u_char read_only; /* True when the device is read-only */ u_char bus_width; /* Bus width to use */ u_char timing; /* Bus timing support */ + uint8_t mem_present; /* Is memory present */ u_char high_cap; /* High Capacity card (block addressed) */ uint32_t sec_count; /* Card capacity in 512byte blocks */ uint32_t tran_speed; /* Max speed in normal mode */ uint32_t hs_tran_speed; /* Max speed in high speed mode */ uint32_t erase_sector; /* Card native erase sector size */ + uint8_t sdio_numfunc; /* Number of IO functions */ char card_id_string[64];/* Formatted CID info (serial, MFG, etc) */ }; @@ -159,10 +178,15 @@ static uint32_t mmc_get_bits(uint32_t *bits, int bit_len, int start, int size); static int mmc_highest_voltage(uint32_t ocr); static void mmc_idle_cards(struct mmc_softc *sc); +static int mmc_io_func_enable(struct mmc_softc *sc, uint32_t fn); +static int mmc_io_rw_direct(struct mmc_softc *sc, int wr, uint32_t fn, + uint32_t adr, uint8_t *data); static void mmc_ms_delay(int ms); static void mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard); static void mmc_power_down(struct mmc_softc *sc); static void mmc_power_up(struct mmc_softc *sc); +static int mmc_probe_sdio(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr, + uint8_t *nfunc, uint8_t *mem_present); static void mmc_rescan_cards(struct mmc_softc *sc); static void mmc_scan(struct mmc_softc *sc); static int mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, @@ -220,6 +244,8 @@ mmc_attach(device_t dev) sc->dev = dev; MMC_LOCK_INIT(sc); + STAILQ_INIT(&sc->sdiof_head); + /* We'll probe and attach our children later, but before / mount */ sc->config_intrhook.ich_func = mmc_delayed_attach; sc->config_intrhook.ich_arg = sc; @@ -470,6 +496,7 @@ mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode, return (0); } +/* CMD0 */ static void mmc_idle_cards(struct mmc_softc *sc) { @@ -494,6 +521,7 @@ mmc_idle_cards(struct mmc_softc *sc) mmc_ms_delay(1); } +/* CMD41 -> CMD55 */ static int mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) { @@ -521,6 +549,7 @@ mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) return (err); } +/* CMD1 */ static int mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) { @@ -548,6 +577,7 @@ mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) return (err); } +/* CMD8 */ static int mmc_send_if_cond(struct mmc_softc *sc, uint8_t vhs) { @@ -600,6 +630,7 @@ mmc_power_down(struct mmc_softc *sc) mmcbr_update_ios(dev); } +/* CMD7 */ static int mmc_select_card(struct mmc_softc *sc, uint16_t rca) { @@ -1042,6 +1073,7 @@ mmc_app_decode_sd_status(uint32_t *raw_sd_status, sd_status->erase_offset = mmc_get_bits(raw_sd_status, 512, 400, 2); } +/* CMD2 */ static int mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid) { @@ -1162,6 +1194,7 @@ mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp) return (err); } +/* CMD3 */ static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp) { @@ -1177,6 +1210,7 @@ mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp) return (err); } +/* CMD13 */ static int mmc_send_status(struct mmc_softc *sc, uint16_t rca, uint32_t *status) { @@ -1223,6 +1257,287 @@ mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard) ivar->read_only ? ", read-only" : ""); } +static int +mmc_io_func_enable(struct mmc_softc *sc, uint32_t fn) +{ + int err, i; + uint8_t funcs; + + /* XXX Check if function number is valid */ + + err = mmc_io_rw_direct(sc, 0, 0, SD_IO_CCCR_FN_READY, &funcs); + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, "Error reading SDIO func ready %d\n", err); + return (err); + } + funcs |= 1 << fn; + err = mmc_io_rw_direct(sc, 1, 0, SD_IO_CCCR_FN_ENABLE, &funcs); + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, "Error writing SDIO func enable %d\n", err); + return (err); + } + + funcs = 0; + for(i=0; i < 10; i++) { + err = mmc_io_rw_direct(sc, 0, 0, SD_IO_CCCR_FN_READY, &funcs); + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, "Error reading SDIO func ready %d\n", err); + return (err); + } + + if (funcs & (1 << fn)) + return 0; + pause("mmc_io_func_enable", 100); + } + + device_printf(sc->dev, "Cannot enable function %d!\n", fn); + return 1; +} + +static int +mmc_io_rw_direct(struct mmc_softc *sc, int wr, uint32_t fn, uint32_t adr, + uint8_t *data) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = SD_IO_RW_DIRECT; + cmd.arg = SD_IO_RW_FUNC(fn) | SD_IO_RW_ADR(adr); + if (wr) + cmd.arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data); + cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + cmd.data = NULL; + + err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + if (err) + return (err); + if (cmd.error) + return (cmd.error); + + if (cmd.resp[0] & R5_COM_CRC_ERROR) + return (MMC_ERR_BADCRC); + if (cmd.resp[0] & (R5_ILLEGAL_COMMAND | R5_FUNCTION_NUMBER)) + return (MMC_ERR_INVALID); + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return (MMC_ERR_FAILED); + + /* Just for information... */ + if (R5_IO_CURRENT_STATE(cmd.resp[0]) != 1) + printf("!!! SDIO state %d\n", R5_IO_CURRENT_STATE(cmd.resp[0])); + + *data = (uint8_t) (cmd.resp[0] & 0xff); + return (MMC_ERR_NONE); +} + +/* CMD52 */ +static uint8_t +mmc_io_read_1(struct mmc_softc *sc, uint32_t fn, uint32_t adr) +{ + int err; + uint8_t val = 0; + + err = mmc_io_rw_direct(sc, 0, fn, adr, &val); + if (err) { + device_printf(sc->dev, "Err reading FN %d addr 0x%08X: %d", + fn, adr, err); + return (0xff); + } + return val; +} + +/* + * Parse Card Information Structure of the SDIO card. + * Both Function 0 CIS and Function 1-7 CIS are supported. + */ +static int +mmc_io_parse_cis(struct mmc_softc *sc, uint8_t func, uint32_t cisptr, struct sdio_function *sdio_func) +{ + uint32_t tmp; + + uint8_t tuple_id, tuple_len, func_id; + uint32_t addr, maninfo_p; + + char *cis1_info[4]; + int start, i, ch, count; + char cis1_info_buf[256]; + + sdio_func->number = func; + + cis1_info[0] = NULL; + cis1_info[1] = NULL; + cis1_info[2] = NULL; + cis1_info[3] = NULL; + memset(cis1_info_buf, 0, 256); + + tmp = 0; + addr = cisptr; + + /* + * XXX Some parts of this code are taken + * from sys/dev/pccard/pccard_cis.c. + * Need to think about making it more abstract. + */ + do { + tuple_id = mmc_io_read_1(sc, 0, addr++); + if (tuple_id == SD_IO_CISTPL_END) + break; + tuple_len = mmc_io_read_1(sc, 0, addr++); + if (tuple_len == 0 && tuple_id != 0x00) { + device_printf(sc->dev, + "Parse error: 0-length tuple %02X\n", tuple_id); + break; + } + + switch (tuple_id) { + case SD_IO_CISTPL_VERS_1: + maninfo_p = addr; + + sdio_func->cis1_major = mmc_io_read_1(sc, 0, maninfo_p); + sdio_func->cis1_minor = mmc_io_read_1(sc, 0, maninfo_p + 1); + + for (count = 0, start = 0, i = 0; + (count < 4) && ((i + 4) < 256); i++) { + ch = mmc_io_read_1(sc, 0, maninfo_p + 2 + i); + if (ch == 0xff) + break; + cis1_info_buf[i] = ch; + if (ch == 0) { + cis1_info[count] = + cis1_info_buf + start; + start = i + 1; + count++; + } + } + + /* + * At least on Dreamplug there is only crap + * in these strings... + */ + device_printf(sc->dev, "*** Info[0]: %s\n", cis1_info[0]); + device_printf(sc->dev, "*** Info[1]: %s\n", cis1_info[1]); + device_printf(sc->dev, "*** Info[2]: %s\n", cis1_info[2]); + device_printf(sc->dev, "*** Info[3]: %s\n", cis1_info[3]); + break; + + case SD_IO_CISTPL_MANFID: + if (tuple_len < 4) { + device_printf(sc->dev, "MANFID is too short\n"); + break; + } + sdio_func->manufacturer = mmc_io_read_1(sc, 0, addr); + sdio_func->manufacturer |= mmc_io_read_1(sc, 0, addr + 1) << 8; + + sdio_func->product = mmc_io_read_1(sc, 0, addr + 2); + sdio_func->product |= mmc_io_read_1(sc, 0, addr + 3) << 8; + break; + + case SD_IO_CISTPL_FUNCID: + /* Function ID for SDIO devices is always 0x0C */ + if (tuple_len < 1) { + device_printf(sc->dev, "FUNCID is too short\n"); + break; + } + func_id = mmc_io_read_1(sc, 0, addr); + if (func_id != 0x0C) + device_printf(sc->dev, "func_id non-std: %d\n", func_id); + break; + + case SD_IO_CISTPL_FUNCE: + if (tuple_len < 4) { + device_printf(sc->dev, "FUNCE is too short\n"); + break; + } + uint8_t ext_data_type = mmc_io_read_1(sc, 0, addr); + + if (func == 0) { + if (ext_data_type != 0x0) + device_printf(sc->dev, + "funce for func 0 non-std: %d\n", + ext_data_type); + sdio_func->fn0_blksize = mmc_io_read_1(sc, 0, addr + 1); + sdio_func->fn0_blksize |= mmc_io_read_1(sc, 0, addr + 2) << 8; + + sdio_func->max_tran_speed = mmc_io_read_1(sc, 0, addr + 3); + /* XXX Do we need this? If yes, need to store in sdio_func */ + uint8_t max_tran_rate = sdio_func->max_tran_speed & 0x3; + uint8_t timecode = (sdio_func->max_tran_speed >> 3) & 0xF; + + device_printf(sc->dev, + "*** Max tran rate %d, timecode %d\n", + max_tran_rate, timecode); + } else { + /* ext_data_type is 1 here */ + /* + * XXX Do we need any information from FUNCE + * for non-0 functions? + */ + device_printf(sc->dev, + "Not parsing FUNCE for func != 0\n"); + } + + break; + + default: + device_printf(sc->dev, + "*** Skipping tuple ID %02X len %02X\n", + tuple_id, tuple_len); + break; + } + + addr += tuple_len; + tmp++; + } while (tuple_id != SD_IO_CISTPL_END && tmp < 10); + + return 0; +} + +/* + * Parse Card Common Control Register of the SDIO card + */ +static int +mmc_io_parse_cccr(struct mmc_softc *sc) +{ + uint32_t cisptr = 0; + + cisptr = mmc_io_read_1(sc, 0, SD_IO_CCCR_CISPTR); + cisptr |= mmc_io_read_1(sc, 0, SD_IO_CCCR_CISPTR + 1) << 8; + cisptr |= mmc_io_read_1(sc, 0, SD_IO_CCCR_CISPTR + 2) << 16; + + if (cisptr < SD_IO_CIS_START || + cisptr > SD_IO_CIS_START + SD_IO_CIS_SIZE) { + device_printf(sc->dev, "Bad CIS pointer in CCCR: %08X\n", cisptr); + return (-1); + } + + return mmc_io_parse_cis(sc, 0, cisptr, &sc->sdio_func0); +} + +/* + * Parse Function Basic Register of the given function + */ +static int +mmc_io_parse_fbr(struct mmc_softc *sc, uint8_t func) +{ + uint32_t fbr_addr, cisptr; + + fbr_addr = SD_IO_FBR_START * func + 0x9; + cisptr = mmc_io_read_1(sc, 0, fbr_addr); + cisptr |= mmc_io_read_1(sc, 0, fbr_addr + 1) << 8; + cisptr |= mmc_io_read_1(sc, 0, fbr_addr + 2) << 16; + + if (cisptr < SD_IO_CIS_START || + cisptr > SD_IO_CIS_START + SD_IO_CIS_SIZE) { + device_printf(sc->dev, "Bad CIS pointer in FBR: %08X\n", cisptr); + return (-1); + } + + struct sdio_function *f = malloc(sizeof(struct sdio_function), M_DEVBUF, M_WAITOK); + STAILQ_INSERT_TAIL(&sc->sdiof_head, f, sdiof_list); + + return mmc_io_parse_cis(sc, func, cisptr, f); +} + static void mmc_discover_cards(struct mmc_softc *sc) { @@ -1233,11 +1548,59 @@ mmc_discover_cards(struct mmc_softc *sc) device_t child; uint16_t rca = 2; u_char switch_res[64]; + uint8_t nfunc, mem_present; if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing cards\n"); while (1) { - err = mmc_all_send_cid(sc, raw_cid); + /* + * Probe SDIO first, because SDIO cards don't have + * a CID register and won't respond to the CMD2 + */ + mmc_idle_cards(sc); + err = mmc_probe_sdio(sc, 0, NULL, &nfunc, &mem_present); + sc->sdio_nfunc = nfunc; + if (err != MMC_ERR_NONE && err != MMC_ERR_TIMEOUT) { + device_printf(sc->dev, "Error probing SDIO %d\n", err); + break; + } + + /* The card answered OK -> SDIO */ + if (err == MMC_ERR_NONE) { + device_printf(sc->dev, "Detected SDIO card\n"); + ivar = malloc(sizeof(struct mmc_ivars), M_DEVBUF, + M_WAITOK | M_ZERO); + mmc_send_relative_addr(sc, &resp); /* CMD3 */ + ivar->rca = resp >> 16; + err = mmc_select_card(sc, ivar->rca); /* CMD7 */ + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, "Error selecting SDIO %d\n", err); + break; + } + + device_printf(sc->dev, "Get card info\n"); + mmc_io_parse_cccr(sc); + for(i=1; i <= nfunc; i++) { + device_printf(sc->dev, + "Get info for function %d\n", i); + mmc_io_parse_fbr(sc, i); + mmc_io_func_enable(sc, i); + } + + device_printf(sc->dev, "=== Functions ===\n"); + struct sdio_function *f; + + STAILQ_FOREACH(f, &sc->sdiof_head, sdiof_list) + device_printf(sc->dev, + "FN %d, vendor %04X, product %04X\n", + f->number, f->manufacturer, f->product + ); + + if (!mem_present) + return; + } + + err = mmc_all_send_cid(sc, raw_cid); /* Command 2 */ if (err == MMC_ERR_TIMEOUT) break; if (err != MMC_ERR_NONE) { @@ -1491,9 +1854,49 @@ mmc_delete_cards(struct mmc_softc *sc) return (0); } +/* CMD 5 */ +static int +mmc_probe_sdio(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr, uint8_t *nfunc, uint8_t *mem_present) { + struct mmc_command cmd; + int err = MMC_ERR_NONE, i; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = IO_SEND_OP_COND; + cmd.arg = 0; + cmd.flags = MMC_RSP_R4; + cmd.data = NULL; + + for (i = 0; i < 1000; i++) { + err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + break; + if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || + (ocr & MMC_OCR_VOLTAGE) == 0) + break; + err = MMC_ERR_TIMEOUT; + mmc_ms_delay(10); + } + + if (err == MMC_ERR_NONE) { + device_printf(sc->dev, "No timeout: OCR %08X, here are the values:\n", cmd.resp[0]); + if (rocr) + *rocr = cmd.resp[0]; + if (nfunc) + *nfunc = cmd.resp[0] >> 28 & 0x7; + if (mem_present) + *mem_present = cmd.resp[0] >> 27 & 0x1; + + device_printf(sc->dev, "NF: %d\n", cmd.resp[0] >> 28 & 0x7); + device_printf(sc->dev, "MEM: %d\n", cmd.resp[0] >> 27 & 0x1); + } + + return (err); +} + static void mmc_go_discovery(struct mmc_softc *sc) { + uint8_t nfunc, mem_present; uint32_t ocr; device_t dev; int err; @@ -1509,17 +1912,24 @@ mmc_go_discovery(struct mmc_softc *sc) if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing bus\n"); mmc_idle_cards(sc); - err = mmc_send_if_cond(sc, 1); + err = mmc_send_if_cond(sc, 1); /* SD_SEND_IF_COND = 8 */ if ((bootverbose || mmc_debug) && err == 0) device_printf(sc->dev, "SD 2.0 interface conditions: OK\n"); - if (mmc_send_app_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { + if (mmc_probe_sdio(sc, 0, &ocr, &nfunc, &mem_present) == MMC_ERR_NONE) { + device_printf(dev, "SDIO probe OK (OCR: 0x%08x, %d functions, memory: %d)\n", ocr, nfunc, mem_present); + if (nfunc > 0 && mem_present) { + device_printf(sc->dev, "SDIO combo cards are not supported yet"); + return; + } + } else + if (mmc_send_app_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { /* retry 55 -> then 41 */ if (bootverbose || mmc_debug) device_printf(sc->dev, "SD probe: failed\n"); /* * Failed, try MMC */ mmcbr_set_mode(dev, mode_mmc); - if (mmc_send_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { + if (mmc_send_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { /* command 1 */ if (bootverbose || mmc_debug) device_printf(sc->dev, "MMC probe: failed\n"); ocr = 0; /* Failed both, powerdown. */ @@ -1553,9 +1963,11 @@ mmc_go_discovery(struct mmc_softc *sc) * Reselect the cards after we've idled them above. */ if (mmcbr_get_mode(dev) == mode_sd) { - err = mmc_send_if_cond(sc, 1); - mmc_send_app_op_cond(sc, - (err ? 0 : MMC_OCR_CCS) | mmcbr_get_ocr(dev), NULL); + if (mem_present) { + err = mmc_send_if_cond(sc, 1); /* CMD 8 */ + mmc_send_app_op_cond(sc, /* 41 -> 55 */ + (err ? 0 : MMC_OCR_CCS) | mmcbr_get_ocr(dev), NULL); + } } else mmc_send_op_cond(sc, mmcbr_get_ocr(dev), NULL); mmc_discover_cards(sc); @@ -1637,7 +2049,7 @@ mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) return (EINVAL); case MMC_IVAR_DSR_IMP: *result = ivar->csd.dsr_imp; - break; + break; case MMC_IVAR_MEDIA_SIZE: *result = ivar->sec_count; break; @@ -1735,3 +2147,4 @@ DRIVER_MODULE(mmc, at91_mci, mmc_driver, mmc_devclass, NULL, NULL); DRIVER_MODULE(mmc, sdhci_pci, mmc_driver, mmc_devclass, NULL, NULL); DRIVER_MODULE(mmc, sdhci_bcm, mmc_driver, mmc_devclass, NULL, NULL); DRIVER_MODULE(mmc, sdhci_fdt, mmc_driver, mmc_devclass, NULL, NULL); +DRIVER_MODULE(mmc, sdio, mmc_driver, mmc_devclass, NULL, NULL); diff --git a/sys/dev/mmc/mmcioreg.h b/sys/dev/mmc/mmcioreg.h new file mode 100644 index 0000000..840a863 --- /dev/null +++ b/sys/dev/mmc/mmcioreg.h @@ -0,0 +1,95 @@ +/* $OpenBSD: sdmmc_ioreg.h,v 1.4 2007/06/02 01:48:37 uwe Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDMMC_IOREG_H +#define _SDMMC_IOREG_H + +/* SDIO commands */ /* response type */ +#define SD_IO_SEND_OP_COND 5 /* R4 */ +#define SD_IO_RW_DIRECT 52 /* R5 */ +#define SD_IO_RW_EXTENDED 53 /* R5? */ + +/* CMD52 arguments */ +#define SD_ARG_CMD52_READ (0<<31) +#define SD_ARG_CMD52_WRITE (1<<31) +#define SD_ARG_CMD52_FUNC_SHIFT 28 +#define SD_ARG_CMD52_FUNC_MASK 0x7 +#define SD_ARG_CMD52_EXCHANGE (1<<27) +#define SD_ARG_CMD52_REG_SHIFT 9 +#define SD_ARG_CMD52_REG_MASK 0x1ffff +#define SD_ARG_CMD52_DATA_SHIFT 0 +#define SD_ARG_CMD52_DATA_MASK 0xff +#define SD_R5_DATA(resp) ((resp)[0] & 0xff) + +/* CMD53 arguments */ +#define SD_ARG_CMD53_READ (0<<31) +#define SD_ARG_CMD53_WRITE (1<<31) +#define SD_ARG_CMD53_FUNC_SHIFT 28 +#define SD_ARG_CMD53_FUNC_MASK 0x7 +#define SD_ARG_CMD53_BLOCK_MODE (1<<27) +#define SD_ARG_CMD53_INCREMENT (1<<26) +#define SD_ARG_CMD53_REG_SHIFT 9 +#define SD_ARG_CMD53_REG_MASK 0x1ffff +#define SD_ARG_CMD53_LENGTH_SHIFT 0 +#define SD_ARG_CMD53_LENGTH_MASK 0x1ff +#define SD_ARG_CMD53_LENGTH_MAX 64 /* XXX should be 511? */ + +/* 48-bit response decoding (32 bits w/o CRC) */ +#define MMC_R4(resp) ((resp)[0]) +#define MMC_R5(resp) ((resp)[0]) + +/* SD R4 response (IO OCR) */ +#define SD_IO_OCR_MEM_READY (1<<31) +#define SD_IO_OCR_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x3) +/* XXX big fat memory present "flag" because we don't know better */ +#define SD_IO_OCR_MEM_PRESENT (0xf<<24) +#define SD_IO_OCR_MASK 0x00fffff0 + +/* Card Common Control Registers (CCCR) */ +#define SD_IO_CCCR_START 0x00000 +#define SD_IO_CCCR_SIZE 0x100 +#define SD_IO_CCCR_FN_ENABLE 0x02 +#define SD_IO_CCCR_FN_READY 0x03 +#define SD_IO_CCCR_INT_ENABLE 0x04 +#define SD_IO_CCCR_CTL 0x06 +#define CCCR_CTL_RES (1<<3) +#define SD_IO_CCCR_BUS_WIDTH 0x07 +#define CCCR_BUS_WIDTH_4 (1<<1) +#define CCCR_BUS_WIDTH_1 (1<<0) +#define SD_IO_CCCR_CISPTR 0x09 /* XXX 9-10, 10-11, or 9-12 */ + +/* Function Basic Registers (FBR) */ +#define SD_IO_FBR_START 0x00100 +#define SD_IO_FBR_SIZE 0x00700 + +/* Card Information Structure (CIS) */ +#define SD_IO_CIS_START 0x01000 +#define SD_IO_CIS_SIZE 0x17000 + +/* CIS tuple codes (based on PC Card 16) */ +#define SD_IO_CISTPL_VERS_1 0x15 +#define SD_IO_CISTPL_MANFID 0x20 +#define SD_IO_CISTPL_FUNCID 0x21 +#define SD_IO_CISTPL_FUNCE 0x22 +#define SD_IO_CISTPL_END 0xff + +/* CISTPL_FUNCID codes */ +/* OpenBSD incorrectly defines 0x0c as FUNCTION_WLAN */ +/* #define SDMMC_FUNCTION_WLAN 0x0c */ +#endif diff --git a/sys/dev/mmc/mmcreg.h b/sys/dev/mmc/mmcreg.h index f454ddb..4b65d91 100644 --- a/sys/dev/mmc/mmcreg.h +++ b/sys/dev/mmc/mmcreg.h @@ -85,6 +85,8 @@ struct mmc_command { #define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY) #define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_PRESENT) +#define MMC_RSP_R4 (MMC_RSP_PRESENT) +#define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC) #define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC) #define MMC_RSP(x) ((x) & MMC_RSP_MASK) @@ -151,6 +153,30 @@ struct mmc_command { #define R1_STATE_PRG 7 #define R1_STATE_DIS 8 +/* + * R5 responses + * + * Types (per SD 2.0 standard) + *e : error bit + *s : status bit + *r : detected and set for the actual command response + *x : Detected and set during command execution. The host can get + * the status by issuing a command with R1 response. + * + * Clear Condition (per SD 2.0 standard) + *a : according to the card current state. + *b : always related to the previous command. reception of a valid + * command will clear it (with a delay of one command). + *c : clear by read + */ +#define R5_COM_CRC_ERROR (1u << 15)/* er, b */ +#define R5_ILLEGAL_COMMAND (1u << 14)/* er, b */ +#define R5_IO_CURRENT_STATE_MASK (3u << 12)/* s, b */ +#define R5_IO_CURRENT_STATE(x) (((x) & R5_IO_CURRENT_STATE_MASK) >> 12) +#define R5_ERROR (1u << 11)/* erx, c */ +#define R5_FUNCTION_NUMBER (1u << 9)/* er, c */ +#define R5_OUT_OF_RANGE (1u << 8)/* er, c */ + struct mmc_data { size_t len; /* size of the data */ size_t xfer_len; @@ -181,7 +207,7 @@ struct mmc_request { #define MMC_SET_RELATIVE_ADDR 3 #define SD_SEND_RELATIVE_ADDR 3 #define MMC_SET_DSR 4 - /* reserved: 5 */ +#define IO_SEND_OP_COND 5 #define MMC_SWITCH_FUNC 6 #define MMC_SWITCH_FUNC_CMDS 0 #define MMC_SWITCH_FUNC_SET 1 @@ -335,6 +361,20 @@ struct mmc_request { #define SD_MAX_HS 50000000 +/* + * SDIO Direct & Extended I/O + */ +#define SD_IO_RW_WR (1u << 31) +#define SD_IO_RW_FUNC(x) (((x) & 0x7) << 28) +#define SD_IO_RW_RAW (1u << 27) +#define SD_IO_RW_INCR (1u << 26) +#define SD_IO_RW_ADR(x) (((x) & 0x1FFFF) << 9) +#define SD_IO_RW_DAT(x) (((x) & 0xFF) << 0) +#define SD_IO_RW_LEN(x) (((x) & 0xFF) << 0) + +#define SD_IOE_RW_LEN(x) (((x) & 0x1FF) << 0) +#define SD_IOE_RW_BLK (1u << 27) + /* OCR bits */ /* From owner-freebsd-embedded@FreeBSD.ORG Wed Jul 3 13:21:15 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id B01812FC for ; Wed, 3 Jul 2013 13:21:15 +0000 (UTC) (envelope-from adrian.chadd@gmail.com) Received: from mail-qc0-x22c.google.com (mail-qc0-x22c.google.com [IPv6:2607:f8b0:400d:c01::22c]) by mx1.freebsd.org (Postfix) with ESMTP id 7636E1C4B for ; Wed, 3 Jul 2013 13:21:15 +0000 (UTC) Received: by mail-qc0-f172.google.com with SMTP id j10so73506qcx.3 for ; Wed, 03 Jul 2013 06:21:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:cc:content-type; bh=X8xuhuRvnSxbmTKwaOvkDh6lYnE87tfOymBa3nCdxec=; b=OcPkH8qCsYZ16h4O3EINhGQj7XMC5I8ogvM+R2uJWpuXOlsKFUEI8OCoM2/PPABQuI VC5A50ItfRz0UK9vqaKQTUZYXOT9bymmp+krfjQv8f4RznG2s4b9ekeDMElZR6WZ811e vKpRkRUf4DS9MU/fzuIaTakryjbJ27I0Pqb5t7XiDh1l/+OR6vuZcu/86u7y3yP4l7Mc qD0dzYRrF6UFC1JNrzPVa/G30K0XmN+O4JYUu1cFvIzKHdkP0FPgYt6FRiZiCxEe5OTN iqlDkz4sPRwzQ44KjwhmhWoVghxWQzb329Em/VOrAJLs8C/Q4ORf2grFF28YXPvA4Pk6 ld7Q== MIME-Version: 1.0 X-Received: by 10.49.132.69 with SMTP id os5mr1157059qeb.48.1372857675044; Wed, 03 Jul 2013 06:21:15 -0700 (PDT) Sender: adrian.chadd@gmail.com Received: by 10.224.52.71 with HTTP; Wed, 3 Jul 2013 06:21:14 -0700 (PDT) In-Reply-To: <18a9b686d7f49d3773ad63eb853b1c88.squirrel@arroway.org> References: <20130701152313.60982@relay.ibs.dn.ua> <20130701220301.1636@relay.ibs.dn.ua> <20130702085213.52064@relay.ibs.dn.ua> <18a9b686d7f49d3773ad63eb853b1c88.squirrel@arroway.org> Date: Wed, 3 Jul 2013 06:21:14 -0700 X-Google-Sender-Auth: 5N3bij4Mb-Jw-5tEejG7DPxqV5A Message-ID: Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? From: Adrian Chadd To: Nenhum_de_Nos Content-Type: text/plain; charset=ISO-8859-1 Cc: freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Jul 2013 13:21:15 -0000 FreeBSD runs on the TL-WR1043nd. It was my first Atheros SoC port. https://wiki.freebsd.org/FreeBSD/mips/TL-WR1043ND -adrian On 2 July 2013 04:41, Nenhum_de_Nos wrote: > > On Tue, July 2, 2013 02:52, Zeus Panchenko wrote: >> Luiz Otavio O Souza wrote: >>> >>> I've successfully used TP-Link MR3220 and MR3420 this way. >>> >> >> thanks for the point >> >> what I in general want from the issue is more or less "common" >> necessities of small (2-10 workplaces) office >> >> and it includes: >> >> - vi >> - pf >> - PPPoE >> - hostapd >> - OpenVPN >> - bsnmpd >> - network utilities >> netstat, ifconfig, route, tcpdump >> - some optional tools >> -- mtr >> -- nrpe >> -- sendmail >> -- tmux/screen >> - anything I missed :) >> >> so, what are the chances to build image with these? > > Hi all, > > I've talked to Luiz some time ago, but I had no time to invest in struggling with the serial > interface. > > As I said before, I have a 1043ND and would really like to see it running FreeBSD. Imagine this > hardware running pfSense ? this would be the dlink killer ;) > > do I need to upload it to the hardware to tinkle with the build script ? First of all I'd like to > help this way, as my shell skills are better then my coding skills :) > > att, > > matheus > > -- > We will call you Cygnus, > The God of balance you shall be > > A: Because it messes up the order in which people normally read text. > Q: Why is top-posting such a bad thing? > > http://en.wikipedia.org/wiki/Posting_style > _______________________________________________ > freebsd-embedded@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-embedded > To unsubscribe, send any mail to "freebsd-embedded-unsubscribe@freebsd.org" From owner-freebsd-embedded@FreeBSD.ORG Wed Jul 3 22:20:10 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id B804A1AD; Wed, 3 Jul 2013 22:20:10 +0000 (UTC) (envelope-from kibab@olymp.kibab.com) Received: from olymp.kibab.com (olymp.kibab.com [5.9.14.202]) by mx1.freebsd.org (Postfix) with ESMTP id 8425C1BD9; Wed, 3 Jul 2013 22:20:09 +0000 (UTC) X-DKIM: OpenDKIM Filter v2.5.2 olymp.kibab.com 2DE8D3F484 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=bakulin.de; s=default; t=1372890002; bh=w3eZJjRCPl4TS9PrAmwgmGCeSbyMVSYuDlBh/F1eVuI=; h=Date:From:To:Cc:Subject:References:In-Reply-To; b=N90/axBtn75L7W7awehjOEYUyh+kb/5X/5CG9Wt+vkIMY+tI0co8VD5fwRsmFsfSH 516VLM3nZ4OdmKePXhd9mhwAPlq2JAXJwzYxi6XxJPZ6zRvdTRufogMTdLE8qCWjNS HQZXl3wAVF4G948/1q/ehG8Bo6cCIL/SJpc64kE4= Date: Thu, 4 Jul 2013 00:20:02 +0200 From: Ilya Bakulin To: Warner Losh Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug Message-ID: <20130703222002.GA60491@olymp.kibab.com> References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> <51D3282C.1090701@bakulin.de> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.21 (2010-09-15) Cc: Alexander Motin , freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Jul 2013 22:20:10 -0000 On Tue, Jul 02, 2013 at 01:34:37PM -0600, Warner Losh wrote: > > On Jul 2, 2013, at 1:21 PM, Ilya Bakulin wrote: > > If we add, say, sdio0 device and store this information there, we end up > > with > > the hierarchy suggested by Ben Gray a year ago. > > Yea, and I didn't like that at all. It violates the FreeBSD device model. OK, I ended up adding some SDIO-related variables directly to mmc_softc. In my understanding, we should treat the SDIO card not as a separate device, but as an extension to the MMC bridge. In particular, things like bus width, timing information and the number of functions obviously belong to the bridge. I have added support for CMD53 today, which is multi-byte data transfer. Additionally, support for setting bus width and clock speed have been added. Now I can successfully do block reads from the card config space. I have found another interesting problem. When reading CIS information using single-byte read, I receive these strings: 0000 0d 21 32 36 25 2c 2c 00 38 30 32 2e 31 31 20 13 |.!26%,,.802.11 .| 0010 04 09 0f 20 09 04 3a 20 32 30 00 00 bf 20 04 9f |... ..: 20... ..| 0020 02 18 91 21 02 0c 00 00 00 00 00 00 00 00 00 00 |...!............| And when using block read, reading the same address in CCCR gives me the following: 0000 4d 61 72 76 65 6c 6c 00 38 30 32 2e 31 31 20 53 |Marvell.802.11 S| 0010 44 49 4f 20 49 44 3a 20 32 30 00 00 ff 20 04 df |DIO ID: 20... ..| So some bytes lack 0x40... This problem occurs also with other numbers read from the card, for example, vendor ID is read as 0x029F instead of 0x02DF. Once this is fixed, I will try to add the code for attaching child devices. diff --git a/sys/arm/conf/KIBAB-DPLUG b/sys/arm/conf/KIBAB-DPLUG new file mode 100644 index 0000000..033d398 --- /dev/null +++ b/sys/arm/conf/KIBAB-DPLUG @@ -0,0 +1,171 @@ +# Kernel config for GlobalScale Technologies DreamPlug version 1001. +# +# This is for units that are version 10, revision 01, with NOR SPI flash. +# These units are identified with the number "1001" on the S/N label. +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ +# + +ident KIBAB-DPLUG + +include "../mv/kirkwood/std.db88f6xxx" + +makeoptions FDT_DTS_FILE=dreamplug-1001.dts + +makeoptions MODULES_OVERRIDE="" + +options SOC_MV_KIRKWOOD + +options SCHED_4BSD #4BSD scheduler +options INET #InterNETworking +options INET6 #IPv6 communications protocols +options SOFTUPDATES +options CD9660 #ISO 9660 filesystem +options FFS #Berkeley Fast Filesystem +options MSDOSFS #MS DOS File System (FAT, FAT32) +options NULLFS #NULL filesystem +options TMPFS #Efficient memory filesystem +options SYSVSHM #SYSV-style shared memory +options SYSVMSG #SYSV-style message queues +options SYSVSEM #SYSV-style semaphores +options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions +options GEOM_ELI # Disk encryption. +options GEOM_LABEL # Providers labelization. +options GEOM_PART_GPT # GPT partitioning + +# Flattened Device Tree +device fdt +options FDT +options FDT_DTB_STATIC + +# Misc pseudo devices +device bpf #Required for DHCP +device faith #IPv6-to-IPv4 relaying (translation) +device firmware #firmware(9) required for USB wlan +device gif #IPv6 and IPv4 tunneling +device loop #Network loopback +device md #Memory/malloc disk +device pty #BSD-style compatibility pseudo ttys +device random #Entropy device +device tun #Packet tunnel. +device ether #Required for all ethernet devices +device vlan #802.1Q VLAN support +device wlan #802.11 WLAN support + +# cam support for umass and ahci +device scbus +device pass +device da +device cd + +# Serial ports +device uart + +# Networking +device mge # Marvell Gigabit Ethernet controller +device mii +device e1000phy + +# USB +options USB_HOST_ALIGN=32 # Align DMA to cacheline +#options USB_DEBUG # Compile in USB debug support +device usb # Basic usb support +device ehci # USB host controller +device umass # Mass storage +device uhid # Human-interface devices +device rum # Ralink Technology RT2501USB wireless NICs + +# I2C (TWSI) +device iic +device iicbus + +# SATA +device mvs +device ahci + +# SDIO +device mv_sdio +device mmcsd +device mmc + +# Sound +device sound +device snd_uaudio + +#crypto +device cesa # Marvell security engine +device crypto +device cryptodev + +# IPSec +device enc +options IPSEC +options IPSEC_NAT_T +options TCP_SIGNATURE #include support for RFC 2385 + +#PF +device pf +device pflog +device pfsync + +# ALTQ, required for PF +options ALTQ # Basic ALTQ support +options ALTQ_CBQ # Class Based Queueing +options ALTQ_RED # Random Early Detection +options ALTQ_RIO # RED In/Out +options ALTQ_HFSC # Hierarchical Packet Scheduler +options ALTQ_CDNR # Traffic conditioner +options ALTQ_PRIQ # Priority Queueing +options ALTQ_NOPCC # Required if the TSC is unusable +#options ALTQ_DEBUG + +# Debugging +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols +options BREAK_TO_DEBUGGER +options ALT_BREAK_TO_DEBUGGER +options DDB +options KDB +options DIAGNOSTIC +options INVARIANTS #Enable calls of extra sanity checking +options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS #Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed +#options WITNESS_KDB + +# Enable these options for nfs root configured via BOOTP. +options NFSCL #Network Filesystem Client +options NFSLOCKD #Network Lock Manager +options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options BOOTP +options BOOTP_NFSROOT +#options BOOTP_NFSV3 +options BOOTP_WIRED_TO=mge0 + +# If not using BOOTP, use something like one of these... +#options ROOTDEVNAME=\"ufs:/dev/da1a\" +#options ROOTDEVNAME=\"ufs:/dev/da1s1a\" +#options ROOTDEVNAME=\"ufs:/dev/da1p10\" +#options ROOTDEVNAME=\"nfs:192.168.0.254/dreamplug\" + +# To use this configuration with the (rare) model 1001N (nand flash), +# create a kernel config file that looks like this: +# +# include DREAMPLUG-1001 +# nomakeoptions FDT_DTS_FILE +# makeoptions FDT_DTS_FILE=dreamplug-1001N.dts +# device nand diff --git a/sys/arm/conf/KIBAB-DPLUG-NODBG b/sys/arm/conf/KIBAB-DPLUG-NODBG new file mode 100644 index 0000000..cbced4a --- /dev/null +++ b/sys/arm/conf/KIBAB-DPLUG-NODBG @@ -0,0 +1,43 @@ +# Kernel config for GlobalScale Technologies DreamPlug version 1001. +# +# This is for units that are version 10, revision 01, with NOR SPI flash. +# These units are identified with the number "1001" on the S/N label. +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ +# + +ident KIBAB-DPLUG-NODBG + +include KIBAB-DPLUG + +# Do not compile FDT in kernel +nomakeoptions FDT_DTS_FILE +nooptions FDT_DTB_STATIC + +# Debugging +nomakeoptions DEBUG +nooptions BREAK_TO_DEBUGGER +nooptions ALT_BREAK_TO_DEBUGGER +nooptions DDB +nooptions KDB +nooptions DIAGNOSTIC +nooptions INVARIANTS #Enable calls of extra sanity checking +nooptions INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS #Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed +#options WITNESS_KDB diff --git a/sys/arm/conf/KIBAB-DPLUG-PROD b/sys/arm/conf/KIBAB-DPLUG-PROD new file mode 100644 index 0000000..bae61a4 --- /dev/null +++ b/sys/arm/conf/KIBAB-DPLUG-PROD @@ -0,0 +1,33 @@ +# Kernel config for GlobalScale Technologies DreamPlug version 1001. +# +# This is for units that are version 10, revision 01, with NOR SPI flash. +# These units are identified with the number "1001" on the S/N label. +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ +# + + +include KIBAB-DPLUG-NODBG + +ident KIBAB-DPLUG-PROD + +nooptions NFS_ROOT +nooptions BOOTP +nooptions BOOTP_NFSROOT +nooptions BOOTP_WIRED_TO + diff --git a/sys/arm/mv/files.mv b/sys/arm/mv/files.mv index 116356d..88c0b98 100644 --- a/sys/arm/mv/files.mv +++ b/sys/arm/mv/files.mv @@ -32,6 +32,7 @@ arm/mv/mv_sata.c optional ata | atamvsata arm/mv/mv_ts.c standard arm/mv/timer.c standard arm/mv/twsi.c optional iicbus +arm/mv/mv_sdio.c optional mv_sdio dev/cesa/cesa.c optional cesa dev/mge/if_mge.c optional mge diff --git a/sys/arm/mv/mv_sdio.c b/sys/arm/mv/mv_sdio.c new file mode 100644 index 0000000..73faf08 --- /dev/null +++ b/sys/arm/mv/mv_sdio.c @@ -0,0 +1,1670 @@ +/*- + * Copyright (c) 2009 Semihalf, Rafal Czubak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Driver for Marvell Integrated SDIO Host Controller. + * Works stable in DMA mode. PIO mode has problems with large data transfers + * (timeouts). + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "mmcbr_if.h" + +#include "mv_sdio.h" + +/* Minimum DMA segment size. */ +#define MV_SDIO_DMA_SEGMENT_SIZE 4096 + +/* Transferred block size. */ +#define MV_SDIO_BLOCK_SIZE 512 + +/* Maximum number of blocks the controller can handle. */ +#define MV_SDIO_BLOCKS_MAX 65535 + +/* Halfword bit masks used for command response extraction. */ +#define MV_SDIO_RSP48_BM2 0x0002 /* Lower 2 bits. */ +#define MV_SDIO_RSP48_BM6 0x003f /* Lower 6 bits. */ +#define MV_SDIO_RSP48_BM16 0xffff /* 16 bits */ + +/* SDIO aggregated command interrupts */ +#define MV_SDIO_IRQS_CMD (MV_SDIO_IRQ_CMD | MV_SDIO_IRQ_UNEXPECTED_RSP) +#define MV_SDIO_EIRQS_CMD (MV_SDIO_EIRQ_CMD_TMO | MV_SDIO_EIRQ_CMD_CRC7 | \ + MV_SDIO_EIRQ_CMD_ENDBIT | MV_SDIO_EIRQ_CMD_INDEX | \ + MV_SDIO_EIRQ_CMD_STARTBIT | MV_SDIO_EIRQ_RSP_TBIT) + +/* SDIO aggregated data interrupts */ +#define MV_SDIO_IRQS_DATA (MV_SDIO_IRQ_XFER | MV_SDIO_IRQ_TX_EMPTY | \ + MV_SDIO_IRQ_RX_FULL | MV_SDIO_IRQ_DMA | MV_SDIO_IRQ_AUTOCMD12) +#define MV_SDIO_EIRQS_DATA (MV_SDIO_EIRQ_DATA_TMO | \ + MV_SDIO_EIRQ_DATA_CRC16 | MV_SDIO_EIRQ_DATA_ENDBIT | \ + MV_SDIO_EIRQ_AUTOCMD12 | MV_SDIO_EIRQ_XFER_SIZE | \ + MV_SDIO_EIRQ_CRC_ENDBIT | MV_SDIO_EIRQ_CRC_STARTBIT | \ + MV_SDIO_EIRQ_CRC_STAT) + +/* + * Timing configuration. + */ + +/* SDIO controller base clock frequency. */ +#define MV_SDIO_F_BASE 100000000 /* 200 MHz */ + +/* Maximum SD clock frequency. */ +#define MV_SDIO_F_MAX (MV_SDIO_F_BASE / 2) /* 50 MHz */ + +/* Maximum timeout value. */ +#define MV_SDIO_TMO_MAX 0xf + +/* Reset delay in microseconds. */ +#define MV_SDIO_RESET_DELAY 10000 /* 10 ms */ + +/* Empty FIFO polling delay. */ +#define MV_SDIO_FIFO_EMPTY_DELAY 1000 /* 1 ms */ + +/* Delays between operations on multiple blocks. */ +#define MV_SDIO_RD_DELAY 50 /*50*/ /* Read access time. */ +#define MV_SDIO_WR_DELAY 10 /*10*/ /* Write access time. */ + +/* Maximum clock divider value. */ +#define MV_SDIO_CLK_DIV_MAX 0x7ff + +struct mv_sdio_softc { + device_t sc_dev; + device_t sc_child; + + bus_space_handle_t sc_bsh; + bus_space_tag_t sc_bst; + + int sc_use_dma; + bus_dma_tag_t sc_dmatag; + bus_dmamap_t sc_dmamap; + uint8_t *sc_dmamem; + bus_addr_t sc_physaddr; + int sc_mapped; + size_t sc_dma_size; + + struct resource *sc_mem_res; + int sc_mem_rid; + + struct resource *sc_irq_res; + int sc_irq_rid; + void *sc_ihl; + + struct resource *sc_cd_irq_res; + int sc_cd_irq_rid; + void *sc_cd_ihl; + + uint32_t sc_irq_mask; + uint32_t sc_eirq_mask; + + struct task sc_card_task; + struct callout sc_card_callout; + + struct mtx sc_mtx; + + int sc_bus_busy; + int sc_card_present; + struct mmc_host sc_host; + struct mmc_request *sc_req; + struct mmc_command *sc_curcmd; + + uint32_t sc_data_offset; +}; + +/* Read/write data from/to registers.*/ +static uint32_t MV_SDIO_RD4(struct mv_sdio_softc *, bus_size_t); +static void MV_SDIO_WR4(struct mv_sdio_softc *, bus_size_t, uint32_t); + +static int mv_sdio_probe(device_t); +static int mv_sdio_attach(device_t); + +static int mv_sdio_read_ivar(device_t, device_t, int, uintptr_t *); +static int mv_sdio_write_ivar(device_t, device_t, int, uintptr_t); + +static int mv_sdio_update_ios(device_t, device_t); +static int mv_sdio_request(device_t, device_t, struct mmc_request *); +static int mv_sdio_get_ro(device_t, device_t); +static int mv_sdio_acquire_host(device_t, device_t); +static int mv_sdio_release_host(device_t, device_t); + +/* Finalizes active MMC request. */ +static void mv_sdio_finalize_request(struct mv_sdio_softc *); + +/* Initializes controller's registers. */ +static void mv_sdio_init(device_t); + +/* Initializes host structure. */ +static void mv_sdio_init_host(struct mv_sdio_softc *); + +/* Used to add and handle sysctls. */ +static void mv_sdio_add_sysctls(struct mv_sdio_softc *); +static int mv_sdio_sysctl_use_dma(SYSCTL_HANDLER_ARGS); + +/* DMA initialization and cleanup functions. */ +static int mv_sdio_dma_init(struct mv_sdio_softc *); +static void mv_sdio_dma_finish(struct mv_sdio_softc *); + +/* DMA map load callback. */ +static void mv_sdio_getaddr(void *, bus_dma_segment_t *, int, int); + +/* Prepare command/data before transaction. */ +static int mv_sdio_start_command(struct mv_sdio_softc *, struct + mmc_command *); +static int mv_sdio_start_data(struct mv_sdio_softc *, struct mmc_data *); + +/* Finish command after transaction. */ +static void mv_sdio_finish_command(struct mv_sdio_softc *); + +/* Response handling. */ +static void mv_sdio_handle_136bit_resp(struct mv_sdio_softc *); +static void mv_sdio_handle_48bit_resp(struct mv_sdio_softc *, + struct mmc_command *); + +/* Interrupt handler and interrupt helper functions. */ +static void mv_sdio_intr(void *); +static void mv_sdio_cmd_intr(struct mv_sdio_softc *, uint32_t, uint32_t); +static void mv_sdio_data_intr(struct mv_sdio_softc *, uint32_t, uint32_t); +static void mv_sdio_disable_intr(struct mv_sdio_softc *); + +/* Used after card detect interrupt has been handled. */ +static void mv_sdio_card_task(void *, int); + +/* Read/write data from FIFO in PIO mode. */ +static uint32_t mv_sdio_read_fifo(struct mv_sdio_softc *); +static void mv_sdio_write_fifo(struct mv_sdio_softc *, uint32_t); + +/* + * PIO mode handling. + * + * Inspired by sdhci(4) driver routines. + */ +static void mv_sdio_transfer_pio(struct mv_sdio_softc *); +static void mv_sdio_read_block_pio(struct mv_sdio_softc *); +static void mv_sdio_write_block_pio(struct mv_sdio_softc *); + + +static device_method_t mv_sdio_methods[] = { + /* device_if */ + DEVMETHOD(device_probe, mv_sdio_probe), + DEVMETHOD(device_attach, mv_sdio_attach), + + /* Bus interface */ + DEVMETHOD(bus_read_ivar, mv_sdio_read_ivar), + DEVMETHOD(bus_write_ivar, mv_sdio_write_ivar), + + /* mmcbr_if */ + DEVMETHOD(mmcbr_update_ios, mv_sdio_update_ios), + DEVMETHOD(mmcbr_request, mv_sdio_request), + DEVMETHOD(mmcbr_get_ro, mv_sdio_get_ro), + DEVMETHOD(mmcbr_acquire_host, mv_sdio_acquire_host), + DEVMETHOD(mmcbr_release_host, mv_sdio_release_host), + + {0, 0}, +}; + +static driver_t mv_sdio_driver = { + "sdio", + mv_sdio_methods, + sizeof(struct mv_sdio_softc), +}; +static devclass_t mv_sdio_devclass; + +DRIVER_MODULE( sdio, simplebus, mv_sdio_driver, mv_sdio_devclass, 0, 0); + + +static __inline uint32_t +MV_SDIO_RD4(struct mv_sdio_softc *sc, bus_size_t off) +{ + + return (bus_read_4(sc->sc_mem_res, off)); +} + +static __inline void +MV_SDIO_WR4(struct mv_sdio_softc *sc, bus_size_t off, uint32_t val) +{ + + bus_write_4(sc->sc_mem_res, off, val); +} + +static int platform_sdio_slot_signal( int signal ) +{ + switch( signal ) + { + case MV_SDIO_SIG_CD: + { + return -1; + break; + } + case MV_SDIO_SIG_WP: + return 0; + break; + default: + return -1; + break; + } + + return 0; +} + +static int +mv_sdio_probe(device_t dev) +{ + uint32_t device, revision; + + if (!ofw_bus_is_compatible(dev, "mrvl,sdio")) + return (ENXIO); + + + soc_id(&device, &revision); + + switch (device) { + case MV_DEV_88F6281: + break; + default: + return (ENXIO); + } + + device_set_desc(dev, "Marvell Integrated SDIO Host Controller"); + + return (BUS_PROBE_SPECIFIC); +} + +static int +mv_sdio_attach(device_t dev) +{ + struct mv_sdio_softc *sc; + int task_initialized = 0; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); + + /* Allocate memory and interrupt resources. */ + sc->sc_mem_rid = 0; + sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->sc_mem_rid, RF_ACTIVE); + + if (sc->sc_mem_res == NULL) { + device_printf(dev, "Could not allocate memory!\n"); + goto fail; + } + + sc->sc_irq_rid = 0; + sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->sc_irq_rid, RF_ACTIVE); + + if (sc->sc_irq_res == NULL) { + device_printf(dev, "Could not allocate IRQ!\n"); + goto fail; + } + + sc->sc_bst = rman_get_bustag(sc->sc_mem_res); + sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res); + + + /* Initialize host controller's registers. */ + mv_sdio_init(dev); + + /* Try to setup DMA. */ + sc->sc_mapped = 0; /* No DMA buffer is mapped. */ + sc->sc_use_dma = 1; /* DMA mode is preferred to PIO mode. */ + + if (mv_sdio_dma_init(sc) < 0) { + device_printf(dev, "Falling back to PIO mode.\n"); + sc->sc_use_dma = 0; + } + + /* Add sysctls. */ + mv_sdio_add_sysctls(sc); + + if (platform_sdio_slot_signal(MV_SDIO_SIG_CD) != -1) { + /* Check if card is present in the slot. */ + if (platform_sdio_slot_signal(MV_SDIO_SIG_CD) == 1) + sc->sc_card_present = 1; + } + + TASK_INIT(&sc->sc_card_task, 0, mv_sdio_card_task, sc); + callout_init(&sc->sc_card_callout, 1); + task_initialized = 1; + + /* Setup interrupt. */ + if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | + INTR_MPSAFE, NULL, mv_sdio_intr, sc, &sc->sc_ihl) != 0) { + device_printf(dev, "Could not setup interrupt!\n"); + goto fail; + } + + /* Host can be acquired. */ + sc->sc_bus_busy = 0; + + /* + * Attach MMC bus only if the card is in the slot or card detect is + * not supported on the platform. + */ + if ((platform_sdio_slot_signal(MV_SDIO_SIG_CD) == -1) || + sc->sc_card_present) { + sc->sc_child = device_add_child(dev, "mmc", -1); + + if (sc->sc_child == NULL) { + device_printf(dev, "Could not add MMC bus!\n"); + goto fail; + } + + /* Initialize host structure for MMC bus. */ + mv_sdio_init_host(sc); + + device_set_ivars(sc->sc_child, &sc->sc_host); + } + + return (bus_generic_attach(dev)); + +fail: + mv_sdio_dma_finish(sc); + if (task_initialized) { + callout_drain(&sc->sc_card_callout); + taskqueue_drain(taskqueue_swi, &sc->sc_card_task); + } + if (sc->sc_ihl != NULL) + bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_ihl); + if (sc->sc_cd_ihl != NULL) + bus_teardown_intr(dev, sc->sc_cd_irq_res, sc->sc_cd_ihl); + if (sc->sc_irq_res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, + sc->sc_irq_res); + if (sc->sc_cd_irq_res != NULL) + bus_release_resource(dev, SYS_RES_IRQ, sc->sc_cd_irq_rid, + sc->sc_cd_irq_res); + if (sc->sc_mem_res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, + sc->sc_mem_res); + mtx_destroy(&sc->sc_mtx); + return (ENXIO); +} + +static int +mv_sdio_update_ios(device_t brdev, device_t reqdev) +{ + struct mv_sdio_softc *sc; + struct mmc_host *host; + struct mmc_ios *ios; + uint32_t xfer, clk_div, host_cr; + + sc = device_get_softc(brdev); + host = device_get_ivars(reqdev); + ios = &host->ios; + + mtx_lock(&sc->sc_mtx); + + if (ios->power_mode == power_off) + /* Re-initialize the controller. */ + mv_sdio_init(brdev); + + xfer = MV_SDIO_RD4(sc, MV_SDIO_XFER); + + if (ios->clock == 0) { + /* Disable clock. */ + xfer |= MV_SDIO_XFER_STOP_CLK; + MV_SDIO_WR4(sc, MV_SDIO_XFER, xfer); + + /* Set maximum clock divider. */ + MV_SDIO_WR4(sc, MV_SDIO_CLK_DIV, MV_SDIO_CLK_DIV_MAX); + } else { + /* + * Calculate and set clock divider. + * Clock rate value is: + * clock = MV_SDIO_F_BASE / (clk_div + 1) + * Thus we calculate the divider value as: + * clk_div = (MV_SDIO_F_BASE / clock) - 1 + */ + clk_div = (MV_SDIO_F_BASE / ios->clock) - 1; + if (clk_div > MV_SDIO_CLK_DIV_MAX) + clk_div = MV_SDIO_CLK_DIV_MAX; + MV_SDIO_WR4(sc, MV_SDIO_CLK_DIV, clk_div); + + /* Enable clock. */ + xfer &= ~MV_SDIO_XFER_STOP_CLK; + MV_SDIO_WR4(sc, MV_SDIO_XFER, xfer); + } + + host_cr = MV_SDIO_RD4(sc, MV_SDIO_HOST_CR); + + /* Set card type. */ + if (host->mode == mode_mmc) + host_cr |= MV_SDIO_HOST_CR_MMC; /* MMC card. */ + else + host_cr &= ~MV_SDIO_HOST_CR_MMC; /* SD card. */ + + /* Set bus width. */ + if (ios->bus_width == bus_width_4) + host_cr |= MV_SDIO_HOST_CR_4BIT; /* 4-bit bus width */ + else + host_cr &= ~MV_SDIO_HOST_CR_4BIT; /* 1-bit bus width */ + + /* Set high/normal speed mode. */ +#if 0 /* Some cards have problems with the highspeed-mode + * Not selecting High-Speed mode enables all cards to work + */ + + if ((ios->timing == bus_timing_hs ) && ( 1 == 0 ) ) + host_cr |= MV_SDIO_HOST_CR_HIGHSPEED; + else +#endif + host_cr &= ~MV_SDIO_HOST_CR_HIGHSPEED; + + MV_SDIO_WR4(sc, MV_SDIO_HOST_CR, host_cr); + + mtx_unlock(&sc->sc_mtx); + + return (0); +} + +static int +mv_sdio_request(device_t brdev, device_t reqdev, struct mmc_request *req) +{ + struct mv_sdio_softc *sc; + int rv; + + sc = device_get_softc(brdev); + rv = EBUSY; + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_req != NULL) { + mtx_unlock(&sc->sc_mtx); + return (rv); + } + + sc->sc_req = req; +/* + device_printf(sc->sc_dev, "cmd %d (hw state 0x%04x)\n", + req->cmd->opcode , MV_SDIO_RD4( sc, MV_SDIO_HOST_SR ) ); +*/ + rv = mv_sdio_start_command(sc, req->cmd); + + mtx_unlock(&sc->sc_mtx); + + return (rv); +} + +static int +mv_sdio_get_ro(device_t brdev, device_t reqdev) +{ + int rv; + + /* Check if card is read only. */ + rv = platform_sdio_slot_signal(MV_SDIO_SIG_WP); + + /* + * Assume that card is not write protected, when platform doesn't + * support WP signal. + */ + if (rv < 0) + rv = 0; + + return (rv); +} + +static int +mv_sdio_acquire_host(device_t brdev, device_t reqdev) +{ + struct mv_sdio_softc *sc; + int rv; + + sc = device_get_softc(brdev); + rv = 0; + + mtx_lock(&sc->sc_mtx); + while (sc->sc_bus_busy) + rv = mtx_sleep(sc, &sc->sc_mtx, PZERO, "sdioah", 0); + sc->sc_bus_busy++; + mtx_unlock(&sc->sc_mtx); + + return (rv); +} + +static int +mv_sdio_release_host(device_t brdev, device_t reqdev) +{ + struct mv_sdio_softc *sc; + + sc = device_get_softc(brdev); + + mtx_lock(&sc->sc_mtx); + sc->sc_bus_busy--; + wakeup(sc); + mtx_unlock(&sc->sc_mtx); + + return (0); +} + +static void +mv_sdio_finalize_request(struct mv_sdio_softc *sc) +{ + struct mmc_request *req; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + req = sc->sc_req; + + if (req) { + /* Finalize active request. */ + /*device_printf(sc->sc_dev, "Finalize request %i\n",req->cmd->opcode);*/ + sc->sc_req = NULL; + sc->sc_curcmd = NULL; + req->done(req); + + + } else + device_printf(sc->sc_dev, "No active request to finalize!\n"); +} + +static void +mv_sdio_init(device_t dev) +{ + struct mv_sdio_softc *sc; + uint32_t host_cr; + + sc = device_get_softc(dev); + + /* Disable interrupts. */ + sc->sc_irq_mask = 0; + sc->sc_eirq_mask = 0; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_EN, sc->sc_eirq_mask); + + /* Clear interrupt status registers. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, MV_SDIO_IRQ_ALL); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, MV_SDIO_EIRQ_ALL); + + /* Enable interrupt status registers. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR_EN, MV_SDIO_IRQ_ALL); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR_EN, MV_SDIO_EIRQ_ALL); + + /* Initialize Host Control Register. */ + host_cr = (MV_SDIO_HOST_CR_PUSHPULL | MV_SDIO_HOST_CR_BE | + MV_SDIO_HOST_CR_TMOVAL(MV_SDIO_TMO_MAX) | MV_SDIO_HOST_CR_TMO); + + MV_SDIO_WR4(sc, MV_SDIO_HOST_CR, host_cr); + + /* Stop clock and reset Transfer Mode Register. */ + MV_SDIO_WR4(sc, MV_SDIO_XFER, MV_SDIO_XFER_STOP_CLK); + + /* Set maximum clock divider value. */ + MV_SDIO_WR4(sc, MV_SDIO_CLK_DIV, MV_SDIO_CLK_DIV_MAX); + + /* Reset status, state machine and FIFOs synchronously. */ + MV_SDIO_WR4(sc, MV_SDIO_SW_RESET, MV_SDIO_SW_RESET_ALL); + DELAY(MV_SDIO_RESET_DELAY); +} + +static void +mv_sdio_init_host(struct mv_sdio_softc *sc) +{ + struct mmc_host *host; + + host = &sc->sc_host; + + /* Clear host structure. */ + bzero(host, sizeof(struct mmc_host)); + + /* Calculate minimum and maximum operating frequencies. */ + host->f_min = MV_SDIO_F_BASE / (MV_SDIO_CLK_DIV_MAX + 1); + host->f_max = MV_SDIO_F_MAX; + + /* Set operation conditions (voltage). */ + host->host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340; + + /* Set additional host controller capabilities. */ + host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_HSPEED; +} + +static void +mv_sdio_add_sysctls(struct mv_sdio_softc *sc) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *children; + struct sysctl_oid *tree; + + ctx = device_get_sysctl_ctx(sc->sc_dev); + children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)); + tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "params", + CTLFLAG_RD, 0, "Driver parameters"); + children = SYSCTL_CHILDREN(tree); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "use_dma", + CTLTYPE_UINT | CTLFLAG_RW, sc, 0, mv_sdio_sysctl_use_dma, + "I", "Use DMA for data transfers (0-1)"); +} + +/* + * This sysctl allows switching between DMA and PIO modes for data transfers: + * + * dev.mv_sdio..params.use_dma + * + * Values: + * + * - 1 sets DMA mode + * - 0 sets PIO mode + * + * Driver uses DMA mode by default. + */ +static int +mv_sdio_sysctl_use_dma(SYSCTL_HANDLER_ARGS) +{ + struct mv_sdio_softc *sc; + uint32_t use_dma; + int error; + + sc = (struct mv_sdio_softc *)arg1; + + use_dma = sc->sc_use_dma; + + error = sysctl_handle_int(oidp, &use_dma, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + + if (use_dma > 1) + return (EINVAL); + + mtx_lock(&sc->sc_mtx); + + /* Check if requested mode is already being used. */ + if (sc->sc_use_dma == use_dma) { + mtx_unlock(&sc->sc_mtx); + return (EPERM); + } + + if (!(sc->sc_mapped)) { + device_printf(sc->sc_dev, "DMA not initialized!\n"); + mtx_unlock(&sc->sc_mtx); + return (ENOMEM); + } + + /* Set new mode. */ + sc->sc_use_dma = use_dma; + + mtx_unlock(&sc->sc_mtx); + + return (0); +} + +static void +mv_sdio_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + + if (error != 0) + return; + + /* Get first segment's physical address. */ + *(bus_addr_t *)arg = segs->ds_addr; +} + +static int +mv_sdio_dma_init(struct mv_sdio_softc *sc) +{ + device_t dev; + bus_size_t dmabuf_size; + + dev = sc->sc_dev; + dmabuf_size = MAXPHYS; + + /* Create DMA tag. */ + if (bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ + MV_SDIO_DMA_SEGMENT_SIZE, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filtfunc, filtfuncarg */ + MAXPHYS, 1, /* maxsize, nsegments */ + MAXPHYS, BUS_DMA_ALLOCNOW, /* maxsegsz, flags */ + NULL, NULL, /* lockfunc, lockfuncarg */ + &sc->sc_dmatag) != 0) { + device_printf(dev, "Could not create DMA tag!\n"); + return (-1); + } + + /* Allocate DMA memory. */ + if (bus_dmamem_alloc(sc->sc_dmatag, (void **)&sc->sc_dmamem, + BUS_DMA_NOWAIT, &sc->sc_dmamap) != 0) { + device_printf(dev, "Could not allocate DMA memory!\n"); + mv_sdio_dma_finish(sc); + return (-1); + } + + /* Find the biggest available DMA buffer size. */ + while (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap, + (void *)sc->sc_dmamem, dmabuf_size, mv_sdio_getaddr, + &sc->sc_physaddr, 0) != 0) { + dmabuf_size >>= 1; + if (dmabuf_size < MV_SDIO_BLOCK_SIZE) { + device_printf(dev, "Could not load DMA map!\n"); + mv_sdio_dma_finish(sc); + return (-1); + } + } + + sc->sc_mapped++; + sc->sc_dma_size = dmabuf_size; + + return (0); +} + +static void +mv_sdio_dma_finish(struct mv_sdio_softc *sc) +{ + + /* Free DMA resources. */ + if (sc->sc_mapped) { + bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap); + sc->sc_mapped--; + } + if (sc->sc_dmamem != NULL) + bus_dmamem_free(sc->sc_dmatag, sc->sc_dmamem, sc->sc_dmamap); + if (sc->sc_dmamap != NULL) + bus_dmamap_destroy(sc->sc_dmatag, sc->sc_dmamap); + if (sc->sc_dmatag != NULL) + bus_dma_tag_destroy(sc->sc_dmatag); +} + +static int +mv_sdio_start_command(struct mv_sdio_softc *sc, struct mmc_command *cmd) +{ + struct mmc_request *req; + uint32_t cmdreg; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + req = sc->sc_req; + + sc->sc_curcmd = cmd; + + cmd->error = MMC_ERR_NONE; + + /* Check if card is in the slot. */ + if ((platform_sdio_slot_signal(MV_SDIO_SIG_CD) != -1) && + (sc->sc_card_present == 0)) { + cmd->error = MMC_ERR_FAILED; + mv_sdio_finalize_request(sc); + return (-1); + } + + /* Check if clock is enabled. */ + if (MV_SDIO_RD4(sc, MV_SDIO_XFER) & MV_SDIO_XFER_STOP_CLK) { + cmd->error = MMC_ERR_FAILED; + mv_sdio_finalize_request(sc); + return (-1); + } + + /* Write command argument. */ + MV_SDIO_WR4(sc, MV_SDIO_CMD_ARGL, cmd->arg & 0xffff); + MV_SDIO_WR4(sc, MV_SDIO_CMD_ARGH, cmd->arg >> 16); + + /* Determine response type. */ + if (cmd->flags & MMC_RSP_136) + cmdreg = MV_SDIO_CMD_RSP_136; + else if (cmd->flags & MMC_RSP_BUSY) + cmdreg = MV_SDIO_CMD_RSP_48_BUSY; + else if (cmd->flags & MMC_RSP_PRESENT) + cmdreg = MV_SDIO_CMD_RSP_48; + else { + /* No response. */ + cmdreg = MV_SDIO_CMD_RSP_NONE; + /* Enable host to detect unexpected response. */ + cmdreg |= MV_SDIO_CMD_UNEXPECTED_RSP; + sc->sc_irq_mask |= MV_SDIO_CMD_UNEXPECTED_RSP; + } + + /* Check command checksum if needed. */ + if (cmd->flags & MMC_RSP_CRC) + cmdreg |= MV_SDIO_CMD_CRC7; + /* Check command opcode if needed. */ + if (cmd->flags & MMC_RSP_OPCODE) + cmdreg |= MV_SDIO_CMD_INDEX_CHECK; + + /* Set commannd opcode. */ + cmdreg |= MV_SDIO_CMD_INDEX(cmd->opcode); + + /* Setup interrupts. */ + sc->sc_irq_mask = MV_SDIO_IRQ_CMD; + sc->sc_eirq_mask = MV_SDIO_EIRQ_ALL; + + /* Prepare data transfer. */ + if (cmd->data) { + cmdreg |= (MV_SDIO_CMD_DATA_PRESENT | MV_SDIO_CMD_DATA_CRC16); + if (mv_sdio_start_data(sc, cmd->data) < 0) { + cmd->error = MMC_ERR_FAILED; + printf("mv_sdio_start_data() failed!\n"); + mv_sdio_finalize_request(sc); + return (-1); + } + } + + /* Write command register. */ + MV_SDIO_WR4(sc, MV_SDIO_CMD, cmdreg); + + /* Clear interrupt status. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, ~MV_SDIO_IRQ_CARD_EVENT /*MV_SDIO_IRQ_ALL*/); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, 0xffff /*MV_SDIO_EIRQ_ALL*/); + + /* Update interrupt/error interrupt enable registers. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_EN, sc->sc_eirq_mask); + + /* Do not complete request, interrupt handler will do this. */ + return (0); +} + +static void +mv_sdio_finish_command(struct mv_sdio_softc *sc) +{ + struct mmc_command *cmd; + struct mmc_data *data; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + cmd = sc->sc_curcmd; + data = cmd->data; + + /* Get response. */ + if (cmd->flags & MMC_RSP_PRESENT) { + if(cmd->flags & MMC_RSP_136) + /* 136-bit response. */ + mv_sdio_handle_136bit_resp(sc); + else + /* 48-bit response. */ + mv_sdio_handle_48bit_resp(sc, NULL); + } + + if (data) { + /* + * Disable command complete interrupt. It has already been + * handled. + */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_CMD; + + /* Enable XFER interrupt. */ + sc->sc_irq_mask |= MV_SDIO_IRQ_XFER; + + /* Check which data interrupts we need to activate. */ + if (sc->sc_use_dma) + /* DMA transaction. */ + sc->sc_irq_mask |= MV_SDIO_IRQ_DMA; + else if (data->flags & MMC_DATA_READ) + /* Read transaction in PIO mode. */ + sc->sc_irq_mask |= MV_SDIO_IRQ_RX_FULL; + else + /* Write transaction in PIO mode. */ + sc->sc_irq_mask |= MV_SDIO_IRQ_TX_EMPTY; + + /* Check if Auto-CMD12 interrupt will be needed. */ + if (sc->sc_req->stop) + sc->sc_irq_mask |= MV_SDIO_IRQ_AUTOCMD12; + + /* Update interrupt enable register. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } else { + /* We're done. Disable interrupts and finalize request. */ + mv_sdio_disable_intr(sc); + mv_sdio_finalize_request(sc); + } +} + +static int +mv_sdio_start_data(struct mv_sdio_softc *sc, struct mmc_data *data) +{ + struct mmc_command *stop; + uint32_t autocmd12reg, xfer, host_sr; + size_t blk_size, blk_count; + int retries; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + /* + * No transfer can be started when FIFO_EMPTY bit in MV_SDIO_HOST_SR + * is not set. This bit is sometimes not set instantly after XFER + * interrupt has been asserted. + */ + host_sr = MV_SDIO_RD4(sc, MV_SDIO_HOST_SR); + + retries = 10; + while (!(host_sr & MV_SDIO_HOST_SR_FIFO_EMPTY)) { + if (retries == 0) + return (-1); + retries--; + DELAY(MV_SDIO_FIFO_EMPTY_DELAY); + host_sr = MV_SDIO_RD4(sc, MV_SDIO_HOST_SR); + } + + /* Clear data offset. */ + sc->sc_data_offset = 0; + + /* + * Set block size. It can be less than or equal to MV_SDIO_BLOCK_SIZE + * bytes. + */ + blk_size = (data->len < MV_SDIO_BLOCK_SIZE) ? data->len : + MV_SDIO_BLOCK_SIZE; + MV_SDIO_WR4(sc, MV_SDIO_BLK_SIZE, blk_size); + + /* Set block count. */ + blk_count = (data->len + MV_SDIO_BLOCK_SIZE - 1) / MV_SDIO_BLOCK_SIZE; + MV_SDIO_WR4(sc, MV_SDIO_BLK_COUNT, blk_count); + + /* We want to initiate transfer by software. */ + xfer = MV_SDIO_XFER_SW_WR_EN; + + if (sc->sc_use_dma) { + /* Synchronize before DMA transfer. */ + if (data->flags & MMC_DATA_READ) + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, + BUS_DMASYNC_PREREAD); + else { + memcpy(sc->sc_dmamem, data->data, data->len); + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, + BUS_DMASYNC_PREWRITE); + } + + /* Write DMA buffer address register. */ + MV_SDIO_WR4(sc, MV_SDIO_DMA_ADDRL, sc->sc_physaddr & 0xffff); + MV_SDIO_WR4(sc, MV_SDIO_DMA_ADDRH, sc->sc_physaddr >> 16); + } else + /* Set PIO transfer mode. */ + xfer |= MV_SDIO_XFER_PIO; + + /* + * Prepare Auto-CMD12. This command is automatically sent to the card + * by the host controller to stop multiple-block data transaction. + */ + if (sc->sc_req->stop) { + stop = sc->sc_req->stop; + + /* Set Auto-CMD12 argument. */ + MV_SDIO_WR4(sc, MV_SDIO_AUTOCMD12_ARGL, stop->arg & 0xffff); + MV_SDIO_WR4(sc, MV_SDIO_AUTOCMD12_ARGH, stop->arg >> 16); + + /* Set Auto-CMD12 opcode. */ + autocmd12reg = MV_SDIO_AUTOCMD12_INDEX(stop->opcode); + + /* Check busy signal if needed. */ + if (stop->flags & MMC_RSP_BUSY) + autocmd12reg |= MV_SDIO_AUTOCMD12_BUSY_CHECK; + /* Check Auto-CMD12 index. */ + if (stop->flags & MMC_RSP_OPCODE) + autocmd12reg |= MV_SDIO_AUTOCMD12_INDEX_CHECK; + + MV_SDIO_WR4(sc, MV_SDIO_AUTOCMD12, autocmd12reg); + + xfer |= MV_SDIO_XFER_AUTOCMD12; + } + + /* Change data direction. */ + if (data->flags & MMC_DATA_READ) + xfer |= MV_SDIO_XFER_TO_HOST; + + /* Write transfer mode register. */ + MV_SDIO_WR4(sc, MV_SDIO_XFER, xfer); + + return (0); +} + +static void +mv_sdio_handle_136bit_resp(struct mv_sdio_softc *sc) +{ + struct mmc_command *cmd; + uint32_t resp[8]; + uint32_t base, extra; + int i, j, off; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + cmd = sc->sc_curcmd; + + /* Collect raw response from the controller. */ + for (i = 0; i < 8; i++) + resp[i] = MV_SDIO_RD4(sc, MV_SDIO_RSP(i)); + + /* Response passed to MMC bus is shifted by one byte. */ + extra = 0; + for (i = 0, j = 7; i < 4; i++, j -= 2) { + off = (i ? 0 : 2); + base = resp[j] | (resp[j - 1] << (16 - off)); + cmd->resp[3 - i] = (base << (6 + off)) + extra; + extra = base >> (26 - off); + } +} + +static void +mv_sdio_handle_48bit_resp(struct mv_sdio_softc *sc, struct mmc_command *stop) +{ + struct mmc_command *cmd; + uint32_t resp[3], word; + uint8_t *rp; + int i; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (stop == NULL) + cmd = sc->sc_curcmd; + else + cmd = stop; + + /* Collect raw response from the controller. */ + for (i = 0; i < 3; i++) { + if (stop == NULL) + resp[i] = MV_SDIO_RD4(sc, MV_SDIO_RSP(i)); + else + resp[i] = MV_SDIO_RD4(sc, MV_SDIO_AUTOCMD12_RSP(i)); + } + + /* Clear MMC bus response buffer. */ + bzero(&cmd->resp[0], 4 * sizeof(uint32_t)); + + /* + * Fill MMC bus response buffer. + */ + + rp = (uint8_t *)&cmd->resp[0]; + + /* Response bits [45:14] */ + word = (resp[1] & MV_SDIO_RSP48_BM16) | + ((resp[0] & MV_SDIO_RSP48_BM16) << 16); + + /* Response bits [15:14] and [13:8] */ + *rp++ = (resp[2] & MV_SDIO_RSP48_BM6) | + ((word & MV_SDIO_RSP48_BM2) << 6); + + /* Response bits [15:14] are already included. */ + word >>= 2; + + /* Response bits [45:16] */ + memcpy(rp, &word, sizeof(uint32_t)); +} + +static void +mv_sdio_intr(void *arg) +{ + struct mv_sdio_softc *sc; + uint32_t irq_stat, eirq_stat; + + sc = (struct mv_sdio_softc *)arg; +#if 0 + device_printf(sc->sc_dev,"intr 0x%04x intr_en 0x%04x hw_state 0x%04x\n", + MV_SDIO_RD4( sc, MV_SDIO_IRQ_SR ) , + MV_SDIO_RD4( sc, MV_SDIO_IRQ_EN ), + MV_SDIO_RD4( sc, MV_SDIO_HOST_SR )); +#endif + + + mtx_lock(&sc->sc_mtx); + + + + irq_stat = MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & sc->sc_irq_mask; + eirq_stat = MV_SDIO_RD4(sc, MV_SDIO_EIRQ_SR) & sc->sc_eirq_mask; + + /* + * In case of error interrupt, interrupt cause will be identified by + * checking bits in error interrupt status register. + */ + irq_stat &= ~MV_SDIO_IRQ_ERR; + + /* Handle command interrupts. */ + if ((irq_stat & MV_SDIO_IRQS_CMD) || + (eirq_stat & MV_SDIO_EIRQS_CMD)) { + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, irq_stat); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, eirq_stat); + mv_sdio_cmd_intr(sc, irq_stat, eirq_stat); + irq_stat &= ~MV_SDIO_IRQS_CMD; + eirq_stat &= ~MV_SDIO_EIRQS_CMD; + } + + /* Handle data interrupts. */ + if ((irq_stat & MV_SDIO_IRQS_DATA) || + (eirq_stat & MV_SDIO_EIRQS_DATA)) { + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, irq_stat); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, eirq_stat); + mv_sdio_data_intr(sc, irq_stat, eirq_stat); + irq_stat &= ~MV_SDIO_IRQS_DATA; + eirq_stat &= ~MV_SDIO_EIRQS_DATA; + } + + /* Handle unexpected interrupts. */ + if (irq_stat) { + device_printf(sc->sc_dev, "Unexpected interrupt(s)! " + "IRQ SR = 0x%08x\n", irq_stat); + /* Clear interrupt status. */ + MV_SDIO_WR4(sc, MV_SDIO_IRQ_SR, irq_stat); + } + if (eirq_stat) { + device_printf(sc->sc_dev, "Unexpected error interrupt(s)! " + "EIRQ SR = 0x%08x\n", eirq_stat); + /* Clear error interrupt status. */ + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_SR, eirq_stat); + } + + mtx_unlock(&sc->sc_mtx); +} + +static void +mv_sdio_cmd_intr(struct mv_sdio_softc *sc, uint32_t irq, uint32_t eirq) +{ + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (!sc->sc_curcmd) { + device_printf(sc->sc_dev, "Got command interrupt, but there " + "is no active command!\n"); + return; + } + + /* Handle unexpected response error. */ + if (irq & MV_SDIO_IRQ_UNEXPECTED_RSP) { + sc->sc_curcmd->error = MMC_ERR_FAILED; + device_printf(sc->sc_dev, "Unexpected response!\n"); + } + + /* Handle errors. */ + if (eirq & MV_SDIO_EIRQ_CMD_TMO) { + sc->sc_curcmd->error = MMC_ERR_TIMEOUT; + device_printf(sc->sc_dev, "Error - command %d timeout!\n", + sc->sc_curcmd->opcode); + } else if (eirq & MV_SDIO_EIRQ_CMD_CRC7) { + sc->sc_curcmd->error = MMC_ERR_BADCRC; + device_printf(sc->sc_dev, "Error - bad command %d " + "checksum!\n", sc->sc_curcmd->opcode); + } else if (eirq) { + sc->sc_curcmd->error = MMC_ERR_FAILED; + device_printf(sc->sc_dev, "Command %d error!\n", + sc->sc_curcmd->opcode); + } + + if (sc->sc_curcmd->error != MMC_ERR_NONE) { + /* Error. Disable interrupts and finalize request. */ + mv_sdio_disable_intr(sc); + mv_sdio_finalize_request(sc); + return; + } + + if (irq & MV_SDIO_IRQ_CMD) + mv_sdio_finish_command(sc); +} + +static void +mv_sdio_data_intr(struct mv_sdio_softc *sc, uint32_t irq, uint32_t eirq) +{ + struct mmc_command *stop; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (!sc->sc_curcmd) { + device_printf(sc->sc_dev, "Got data interrupt, but there is " + "no active command.\n"); + return; + } + if ((!sc->sc_curcmd->data) && ((sc->sc_curcmd->flags & + MMC_RSP_BUSY) == 0)) { + device_printf(sc->sc_dev, "Got data interrupt, but there is " + "no active data transaction.n\n"); + sc->sc_curcmd->error = MMC_ERR_FAILED; + return; + } + + /* Handle errors. */ + if(eirq & MV_SDIO_EIRQ_DATA_TMO) { + sc->sc_curcmd->error = MMC_ERR_TIMEOUT; + device_printf(sc->sc_dev, "Data %s timeout!\n", + (sc->sc_curcmd->data->flags & MMC_DATA_READ) ? "read" : + "write"); + } else if (eirq & (MV_SDIO_EIRQ_DATA_CRC16 | + MV_SDIO_EIRQ_DATA_ENDBIT)) { + sc->sc_curcmd->error = MMC_ERR_BADCRC; + device_printf(sc->sc_dev, "Bad data checksum!\n"); + } else if (eirq) { + sc->sc_curcmd->error = MMC_ERR_FAILED; + device_printf(sc->sc_dev, "Data error!: 0x%04X \n", + eirq); + + if( 0 != ( eirq & MV_SDIO_EIRQ_CRC_STAT ) ) + { + device_printf(sc->sc_dev, "MV_SDIO_EIRQ_CRC_STAT\n"); + } + } + + /* Handle Auto-CMD12 error. */ + if (eirq & MV_SDIO_EIRQ_AUTOCMD12) { + sc->sc_req->stop->error = MMC_ERR_FAILED; + sc->sc_curcmd->error = MMC_ERR_FAILED; + device_printf(sc->sc_dev, "Auto-CMD12 error!\n"); + } + + if (sc->sc_curcmd->error != MMC_ERR_NONE) { + /* Error. Disable interrupts and finalize request. */ + mv_sdio_disable_intr(sc); + mv_sdio_finalize_request(sc); + return; + } + + /* Handle PIO interrupt. */ + if (irq & (MV_SDIO_IRQ_TX_EMPTY | MV_SDIO_IRQ_RX_FULL)) + mv_sdio_transfer_pio(sc); + + /* Handle DMA interrupt. */ + if (irq & (MV_SDIO_IRQ_DMA)) { + /* Synchronize DMA buffer. */ + if (MV_SDIO_RD4(sc, MV_SDIO_XFER) & MV_SDIO_XFER_TO_HOST) { + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, + BUS_DMASYNC_POSTWRITE); + memcpy(sc->sc_curcmd->data->data, sc->sc_dmamem, + sc->sc_curcmd->data->len); + } else + bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, + BUS_DMASYNC_POSTREAD); + + /* Disable DMA interrupt. */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_DMA; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } + + /* Handle Auto-CMD12 interrupt. */ + if (irq & (MV_SDIO_IRQ_AUTOCMD12)) { + stop = sc->sc_req->stop; + /* Get 48-bit response. */ + mv_sdio_handle_48bit_resp(sc, stop); + + /* Disable Auto-CMD12 interrupt. */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_AUTOCMD12; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } + + /* Transfer finished. Disable interrupts and finalize request. */ + if (irq & (MV_SDIO_IRQ_XFER)) { + mv_sdio_disable_intr(sc); + mv_sdio_finalize_request(sc); + } +} + +static void +mv_sdio_disable_intr(struct mv_sdio_softc *sc) +{ + + /* Disable interrupts that were enabled. */ + sc->sc_irq_mask &= ~(sc->sc_irq_mask); + sc->sc_eirq_mask &= ~(sc->sc_eirq_mask); + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + MV_SDIO_WR4(sc, MV_SDIO_EIRQ_EN, sc->sc_eirq_mask); +} + +static void +mv_sdio_card_task(void *arg, int pending) +{ + struct mv_sdio_softc *sc; + + int device_probe_and_attach_ret_val = 0; + + sc = (struct mv_sdio_softc *)arg; + + mtx_lock(&sc->sc_mtx); + + if (sc->sc_card_present) { + if (sc->sc_child) { + mtx_unlock(&sc->sc_mtx); + return; + } + + /* Initialize host controller's registers. */ + mv_sdio_init(sc->sc_dev); + + sc->sc_child = device_add_child(sc->sc_dev, "mmc", -1); + if (sc->sc_child == NULL) { + device_printf(sc->sc_dev, "Could not add MMC bus!\n"); + mtx_unlock(&sc->sc_mtx); + return; + } + + /* Initialize host structure for MMC bus. */ + mv_sdio_init_host(sc); + + device_set_ivars(sc->sc_child, &sc->sc_host); + + mtx_unlock(&sc->sc_mtx); + + device_probe_and_attach_ret_val = device_probe_and_attach(sc->sc_child); + + if( 0 != device_probe_and_attach_ret_val ) { + device_printf(sc->sc_dev, "MMC bus failed on probe " + "and attach! %i\n",device_probe_and_attach_ret_val); + device_delete_child(sc->sc_dev, sc->sc_child); + sc->sc_child = NULL; + } + } else { + if (sc->sc_child == NULL) { + mtx_unlock(&sc->sc_mtx); + return; + } + + mtx_unlock(&sc->sc_mtx); + if (device_delete_child(sc->sc_dev, sc->sc_child) != 0) { + device_printf(sc->sc_dev, "Could not delete MMC " + "bus!\n"); + } + sc->sc_child = NULL; + } +} + +static uint32_t +mv_sdio_read_fifo(struct mv_sdio_softc *sc) +{ + uint32_t data; + device_printf(sc->sc_dev, "This is not tested, yet MV_SDIO_FIFO not ensured\n "); + + while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_RX_FULL)); + data = MV_SDIO_RD4(sc, MV_SDIO_FIFO); + while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_RX_FULL)); + data |= (MV_SDIO_RD4(sc, MV_SDIO_FIFO) << 16); + return data; +} + +static void +mv_sdio_write_fifo(struct mv_sdio_softc *sc, uint32_t val) +{ + while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_TX_EMPTY)); + MV_SDIO_WR4(sc, MV_SDIO_FIFO, val & 0xffff); + while (!(MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & MV_SDIO_IRQ_TX_EMPTY)); + MV_SDIO_WR4(sc, MV_SDIO_FIFO, val >> 16); +} + +static void +mv_sdio_transfer_pio(struct mv_sdio_softc *sc) +{ + struct mmc_command *cmd; + + cmd = sc->sc_curcmd; + + if (cmd->data->flags & MMC_DATA_READ) { + while (MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & + MV_SDIO_IRQ_RX_FULL) { + mv_sdio_read_block_pio(sc); + /* + * Assert delay after each block transfer to meet read + * access timing constraint. + */ + DELAY(MV_SDIO_RD_DELAY); + if (sc->sc_data_offset >= cmd->data->len) + break; + } + /* All blocks read in PIO mode. Disable interrupt. */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_RX_FULL; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } else { + while (MV_SDIO_RD4(sc, MV_SDIO_IRQ_SR) & + MV_SDIO_IRQ_TX_EMPTY) { + mv_sdio_write_block_pio(sc); + /* Wait while card is programming the memory. */ + while ((MV_SDIO_RD4(sc, MV_SDIO_HOST_SR) & + MV_SDIO_HOST_SR_CARD_BUSY)); + /* + * Assert delay after each block transfer to meet + * write access timing constraint. + */ + DELAY(MV_SDIO_WR_DELAY); + + if (sc->sc_data_offset >= cmd->data->len) + break; + } + /* All blocks written in PIO mode. Disable interrupt. */ + sc->sc_irq_mask &= ~MV_SDIO_IRQ_TX_EMPTY; + MV_SDIO_WR4(sc, MV_SDIO_IRQ_EN, sc->sc_irq_mask); + } +} + +static void +mv_sdio_read_block_pio(struct mv_sdio_softc *sc) +{ + uint32_t data; + char *buffer; + size_t left; + + buffer = sc->sc_curcmd->data->data; + buffer += sc->sc_data_offset; + /* Transfer one block at a time. */ + left = min(MV_SDIO_BLOCK_SIZE, sc->sc_curcmd->data->len - + sc->sc_data_offset); + sc->sc_data_offset += left; + + /* Handle unaligned and aligned buffer cases. */ + if ((intptr_t)buffer & 3) { + while (left > 3) { + data = mv_sdio_read_fifo(sc); + buffer[0] = data; + buffer[1] = (data >> 8); + buffer[2] = (data >> 16); + buffer[3] = (data >> 24); + buffer += 4; + left -= 4; + } + } else { + while (left > 3) { + data = mv_sdio_read_fifo(sc); + *((uint32_t *)buffer) = data; + buffer += 4; + left -= 4; + } + } + /* Handle uneven size case. */ + if (left > 0) { + data = mv_sdio_read_fifo(sc); + while (left > 0) { + *(buffer++) = data; + data >>= 8; + left--; + } + } +} + +static void +mv_sdio_write_block_pio(struct mv_sdio_softc *sc) +{ + uint32_t data = 0; + char *buffer; + size_t left; + + buffer = sc->sc_curcmd->data->data; + buffer += sc->sc_data_offset; + /* Transfer one block at a time. */ + left = min(MV_SDIO_BLOCK_SIZE, sc->sc_curcmd->data->len - + sc->sc_data_offset); + sc->sc_data_offset += left; + + /* Handle unaligned and aligned buffer cases. */ + if ((intptr_t)buffer & 3) { + while (left > 3) { + data = buffer[0] + + (buffer[1] << 8) + + (buffer[2] << 16) + + (buffer[3] << 24); + left -= 4; + buffer += 4; + mv_sdio_write_fifo(sc, data); + } + } else { + while (left > 3) { + data = *((uint32_t *)buffer); + left -= 4; + buffer += 4; + mv_sdio_write_fifo(sc, data); + } + } + /* Handle uneven size case. */ + if (left > 0) { + data = 0; + while (left > 0) { + data <<= 8; + data += *(buffer++); + left--; + } + mv_sdio_write_fifo(sc, data); + } +} + +static int +mv_sdio_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) +{ + struct mv_sdio_softc *sc; + struct mmc_host *host; + + sc = device_get_softc(dev); + host = device_get_ivars(child); + + switch (index) { + case MMCBR_IVAR_BUS_MODE: + *(int *)result = host->ios.bus_mode; + break; + case MMCBR_IVAR_BUS_WIDTH: + *(int *)result = host->ios.bus_width; + break; + case MMCBR_IVAR_CHIP_SELECT: + *(int *)result = host->ios.chip_select; + break; + case MMCBR_IVAR_CLOCK: + *(int *)result = host->ios.clock; + break; + case MMCBR_IVAR_F_MIN: + *(int *)result = host->f_min; + break; + case MMCBR_IVAR_F_MAX: + *(int *)result = host->f_max; + break; + case MMCBR_IVAR_HOST_OCR: + *(int *)result = host->host_ocr; + break; + case MMCBR_IVAR_MODE: + *(int *)result = host->mode; + break; + case MMCBR_IVAR_OCR: + *(int *)result = host->ocr; + break; + case MMCBR_IVAR_POWER_MODE: + *(int *)result = host->ios.power_mode; + break; + case MMCBR_IVAR_VDD: + *(int *)result = host->ios.vdd; + break; + case MMCBR_IVAR_CAPS: + *(int *)result = host->caps; + break; + case MMCBR_IVAR_TIMING: + *(int *)result = host->ios.timing; + break; + case MMCBR_IVAR_MAX_DATA: + mtx_lock(&sc->sc_mtx); + /* Return maximum number of blocks the driver can handle. */ + if (sc->sc_use_dma) + *(int *)result = (sc->sc_dma_size / + MV_SDIO_BLOCK_SIZE); + else + *(int *)result = MV_SDIO_BLOCKS_MAX; + mtx_unlock(&sc->sc_mtx); + break; + default: + return (EINVAL); + } + + return (0); +} + +static int +mv_sdio_write_ivar(device_t dev, device_t child, int index, uintptr_t value) +{ + struct mmc_host *host; + + host = device_get_ivars(child); + + switch (index) { + case MMCBR_IVAR_BUS_MODE: + host->ios.bus_mode = value; + break; + case MMCBR_IVAR_BUS_WIDTH: + host->ios.bus_width = value; + break; + case MMCBR_IVAR_CHIP_SELECT: + host->ios.chip_select = value; + break; + case MMCBR_IVAR_CLOCK: + host->ios.clock = value; + break; + case MMCBR_IVAR_MODE: + host->mode = value; + break; + case MMCBR_IVAR_OCR: + host->ocr = value; + break; + case MMCBR_IVAR_POWER_MODE: + host->ios.power_mode = value; + break; + case MMCBR_IVAR_VDD: + host->ios.vdd = value; + break; + case MMCBR_IVAR_TIMING: + host->ios.timing = value; + break; + case MMCBR_IVAR_CAPS: + case MMCBR_IVAR_HOST_OCR: + case MMCBR_IVAR_F_MIN: + case MMCBR_IVAR_F_MAX: + case MMCBR_IVAR_MAX_DATA: + default: + /* Instance variable not writable. */ + return (EINVAL); + } + + return (0); +} + diff --git a/sys/arm/mv/mv_sdio.h b/sys/arm/mv/mv_sdio.h new file mode 100644 index 0000000..b54b59d --- /dev/null +++ b/sys/arm/mv/mv_sdio.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2008 Marvell Semiconductors, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _MVSDMMC_INCLUDE +#define _MVSDMMC_INCLUDE + + +#define MVSDMMC_DMA_SIZE 65536 + + + +/* + * The base MMC clock rate + */ + +#define MVSDMMC_CLOCKRATE_MIN 100000 +#define MVSDMMC_CLOCKRATE_MAX 50000000 + +#define MVSDMMC_BASE_FAST_CLOCK 200000000 + + +/* + * SDIO register + */ + +#define MV_SDIO_DMA_ADDRL 0x000 +#define MV_SDIO_DMA_ADDRH 0x004 +#define MV_SDIO_BLK_SIZE 0x008 +#define MV_SDIO_BLK_COUNT 0x00c +#define MV_SDIO_CMD 0x01c +#define MV_SDIO_CMD_ARGL 0x010 +#define MV_SDIO_CMD_ARGH 0x014 +#define MV_SDIO_XFER 0x018 +#define MV_SDIO_HOST_SR 0x048 +#define MV_SDIO_HOST_CR 0x050 +#define MV_SDIO_SW_RESET 0x05c +#define MV_SDIO_IRQ_SR 0x060 +#define MV_SDIO_EIRQ_SR 0x064 +#define MV_SDIO_IRQ_SR_EN 0x068 +#define MV_SDIO_EIRQ_SR_EN 0x06c +#define MV_SDIO_IRQ_EN 0x070 +#define MV_SDIO_EIRQ_EN 0x074 +#define MV_SDIO_AUTOCMD12_ARGL 0x084 +#define MV_SDIO_AUTOCMD12_ARGH 0x088 +#define MV_SDIO_AUTOCMD12 0x08c +#define MV_SDIO_CLK_DIV 0x128 +#define MV_SDIO_FIFO 0xa2100 /* FIXME!!! */ + +#define MV_SDIO_RSP(i) (0x020 + ((i)<<2)) +#define MV_SDIO_AUTOCMD12_RSP(i) (0x090 + ((i)<<2)) + +/* + * SDIO Status-Register + */ +#define MV_SDIO_HOST_SR_CARD_BUSY (1<<1) +#define MV_SDIO_HOST_SR_FIFO_EMPTY (1<<13) + + + +/* + * SDIO_CMD + */ +#define MV_SDIO_CMD_RSP_NONE (0 << 0) +#define MV_SDIO_CMD_RSP_136 (1 << 0) +#define MV_SDIO_CMD_RSP_48 (2 << 0) +#define MV_SDIO_CMD_RSP_48_BUSY (3 << 0) +#define MV_SDIO_CMD_DATA_CRC16 (1<<2) +#define MV_SDIO_CMD_CRC7 (1<<3) +#define MV_SDIO_CMD_INDEX_CHECK (1<<4) +#define MV_SDIO_CMD_DATA_PRESENT (1<<5) +#define MV_SDIO_CMD_UNEXPECTED_RSP (1<<7) +#define MV_SDIO_CMD_INDEX(x) ( (x) << 8 ) + + +/* + * SDIO_XFER_MODE + */ +#define MV_SDIO_XFER_STOP_CLK (1 << 5) +#define MV_SDIO_XFER_TO_HOST (1 << 4) +#define MV_SDIO_XFER_PIO (1 << 3) +#define MV_SDIO_XFER_AUTOCMD12 (1 << 2) +#define MV_SDIO_XFER_SW_WR_EN (1 << 1) + +/* + * SDIO_HOST_CTRL + */ +#define MV_SDIO_HOST_CR_PUSHPULL (1 << 0) +#define MV_SDIO_HOST_CR_MMC (3 << 1) +#define MV_SDIO_HOST_CR_BE (1 << 3) +#define MV_SDIO_HOST_CR_4BIT (1 << 9) +#define MV_SDIO_HOST_CR_HIGHSPEED (1 << 10) + +#define MV_SDIO_HOST_CR_TMOVAL(x) ((x) << 11) +#define MV_SDIO_HOST_CR_TMO ( 1 << 15 ) + +/* + * NORmal status bits + */ + + +#define MV_SDIO_IRQ_ERR (1<<15) +#define MV_SDIO_IRQ_UNEXPECTED_RSP (1<<14) +#define MV_SDIO_IRQ_AUTOCMD12 (1<<13) +#define MV_SDIO_IRQ_SUSPENSE_ON_IRQ_EN (1<<12) +#define MV_SDIO_IRQ_IMB_FIFO_WORD_AVAIL (1<<11) +#define MV_SDIO_IRQ_IMB_FIFO_WORD_FILLED (1<<10) +#define MV_SDIO_IRQ_READ_WAIT (1<<9) +#define MV_SDIO_IRQ_CARD_EVENT (1<<8) +#define MV_SDIO_IRQ_RX_FULL (1<<5) +#define MV_SDIO_IRQ_TX_EMPTY (1<<4) +#define MV_SDIO_IRQ_DMA (1<<3) +#define MV_SDIO_IRQ_BLOCK_GAP (1<<2) +#define MV_SDIO_IRQ_XFER (1<<1) +#define MV_SDIO_IRQ_CMD (1<<0) + +#define MV_SDIO_IRQ_ALL (MV_SDIO_IRQ_CMD | MV_SDIO_IRQ_XFER | MV_SDIO_IRQ_BLOCK_GAP | MV_SDIO_IRQ_DMA | MV_SDIO_IRQ_RX_FULL | MV_SDIO_IRQ_TX_EMPTY | MV_SDIO_IRQ_CARD_EVENT | MV_SDIO_IRQ_READ_WAIT | MV_SDIO_IRQ_IMB_FIFO_WORD_FILLED | MV_SDIO_IRQ_IMB_FIFO_WORD_AVAIL | MV_SDIO_IRQ_SUSPENSE_ON_IRQ_EN | MV_SDIO_IRQ_AUTOCMD12 | MV_SDIO_IRQ_UNEXPECTED_RSP | MV_SDIO_IRQ_ERR ) + +//#define MV_SDIO_IRQ_SR + + +/* + * ERR status bits + */ +#define MV_SDIO_EIRQ_CRC_STAT (1<<14) +#define MV_SDIO_EIRQ_CRC_STARTBIT (1<<13) +#define MV_SDIO_EIRQ_CRC_ENDBIT (1<<12) +#define MV_SDIO_EIRQ_RSP_TBIT (1<<11) +#define MV_SDIO_EIRQ_XFER_SIZE (1<<10) +#define MV_SDIO_EIRQ_CMD_STARTBIT (1<<9) +#define MV_SDIO_EIRQ_AUTOCMD12 (1<<8) +#define MV_SDIO_EIRQ_DATA_ENDBIT (1<<6) +#define MV_SDIO_EIRQ_DATA_CRC16 (1<<5) +#define MV_SDIO_EIRQ_DATA_TMO (1<<4) +#define MV_SDIO_EIRQ_CMD_INDEX (1<<3) +#define MV_SDIO_EIRQ_CMD_ENDBIT (1<<2) +#define MV_SDIO_EIRQ_CMD_CRC7 (1<<1) +#define MV_SDIO_EIRQ_CMD_TMO (1<<0) + +#define MV_SDIO_EIRQ_ALL (MV_SDIO_EIRQ_CMD_TMO | \ + MV_SDIO_EIRQ_CMD_CRC7 | \ + MV_SDIO_EIRQ_CMD_ENDBIT | \ + MV_SDIO_EIRQ_CMD_INDEX | \ + MV_SDIO_EIRQ_DATA_TMO | \ + MV_SDIO_EIRQ_DATA_CRC16 | \ + MV_SDIO_EIRQ_DATA_ENDBIT | \ + MV_SDIO_EIRQ_AUTOCMD12 | \ + MV_SDIO_EIRQ_CMD_STARTBIT |\ + MV_SDIO_EIRQ_XFER_SIZE |\ + MV_SDIO_EIRQ_RSP_TBIT |\ + MV_SDIO_EIRQ_CRC_ENDBIT |\ + MV_SDIO_EIRQ_CRC_STARTBIT |\ + MV_SDIO_EIRQ_CRC_STAT) + +/* AUTOCMD12 register values */ +#define MV_SDIO_AUTOCMD12_BUSY_CHECK (1<<0) +#define MV_SDIO_AUTOCMD12_INDEX_CHECK (1<<1) +#define MV_SDIO_AUTOCMD12_INDEX(x) (x<<8) + +/* Software reset register */ +#define MV_SDIO_SW_RESET_ALL (1<<8) + +/* */ +#define MV_SDIO_SIG_CD 1 +#define MV_SDIO_SIG_WP 2 + +#endif /* _MVSDMMC_INCLUDE */ + diff --git a/sys/boot/uboot/common/main.c b/sys/boot/uboot/common/main.c index 82c86b2..0a5b368 100644 --- a/sys/boot/uboot/common/main.c +++ b/sys/boot/uboot/common/main.c @@ -122,6 +122,7 @@ main(void) struct api_signature *sig = NULL; int i; struct open_file f; + char *ub_currdev; if (!api_search_sig(&sig)) return (-1); @@ -166,6 +167,7 @@ main(void) printf("(%s, %s)\n", bootprog_maker, bootprog_date); meminfo(); + ub_currdev = ub_env_get("currdev"); /* * March through the device switch probing for things. */ @@ -198,8 +200,13 @@ main(void) if (devsw[i] == NULL) panic("No boot device found!"); - env_setenv("currdev", EV_VOLATILE, uboot_fmtdev(&currdev), - uboot_setcurrdev, env_nounset); + if (ub_currdev) { + env_setenv("currdev", EV_VOLATILE, ub_currdev, + uboot_setcurrdev, env_nounset); + } else { + env_setenv("currdev", EV_VOLATILE, uboot_fmtdev(&currdev), + uboot_setcurrdev, env_nounset); + } env_setenv("loaddev", EV_VOLATILE, uboot_fmtdev(&currdev), env_noset, env_nounset); diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c index f101e65..53c51de 100644 --- a/sys/dev/mmc/mmc.c +++ b/sys/dev/mmc/mmc.c @@ -67,15 +67,38 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include + #include "mmcbr_if.h" #include "mmcbus_if.h" +/* CIS structure of SDIO card */ +struct sdio_function { + int number; + uint8_t cis1_major; + uint8_t cis1_minor; + uint16_t manufacturer; + uint16_t product; + uint16_t max_blksize; + uint8_t max_tran_speed; /* only for func0 */ + STAILQ_ENTRY(sdio_function) sdiof_list; +}; + struct mmc_softc { device_t dev; struct mtx sc_mtx; struct intr_config_hook config_intrhook; device_t owner; uint32_t last_rca; + uint32_t __sdio_rca; /* XXX Temp; for testng only */ + uint32_t __sdio_cis1_info; + uint8_t sdio_nfunc; + u_char sdio_bus_width; + uint8_t sdio_support_hs; + u_char sdio_timing; + uint32_t sdio_tran_speed; + struct sdio_function sdio_func0; + STAILQ_HEAD(, sdio_function) sdiof_head; }; /* @@ -102,6 +125,7 @@ struct mmc_ivars { uint32_t hs_tran_speed; /* Max speed in high speed mode */ uint32_t erase_sector; /* Card native erase sector size */ char card_id_string[64];/* Formatted CID info (serial, MFG, etc) */ + struct sdio_function *sdiof; }; #define CMD_RETRIES 3 @@ -159,10 +183,16 @@ static uint32_t mmc_get_bits(uint32_t *bits, int bit_len, int start, int size); static int mmc_highest_voltage(uint32_t ocr); static void mmc_idle_cards(struct mmc_softc *sc); +static int mmc_io_func_enable(struct mmc_softc *sc, uint32_t fn); +static uint8_t mmc_io_read_1(struct mmc_softc *sc, uint32_t fn, uint32_t adr); +static int mmc_io_rw_direct(struct mmc_softc *sc, int wr, uint32_t fn, + uint32_t adr, uint8_t *data); static void mmc_ms_delay(int ms); static void mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard); static void mmc_power_down(struct mmc_softc *sc); static void mmc_power_up(struct mmc_softc *sc); +static int mmc_probe_sdio(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr, + uint8_t *nfunc, uint8_t *mem_present); static void mmc_rescan_cards(struct mmc_softc *sc); static void mmc_scan(struct mmc_softc *sc); static int mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, @@ -220,6 +250,8 @@ mmc_attach(device_t dev) sc->dev = dev; MMC_LOCK_INIT(sc); + STAILQ_INIT(&sc->sdiof_head); + /* We'll probe and attach our children later, but before / mount */ sc->config_intrhook.ich_func = mmc_delayed_attach; sc->config_intrhook.ich_arg = sc; @@ -470,6 +502,7 @@ mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode, return (0); } +/* CMD0 */ static void mmc_idle_cards(struct mmc_softc *sc) { @@ -494,6 +527,7 @@ mmc_idle_cards(struct mmc_softc *sc) mmc_ms_delay(1); } +/* CMD41 -> CMD55 */ static int mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) { @@ -521,6 +555,7 @@ mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) return (err); } +/* CMD1 */ static int mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) { @@ -548,6 +583,7 @@ mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr) return (err); } +/* CMD8 */ static int mmc_send_if_cond(struct mmc_softc *sc, uint8_t vhs) { @@ -600,6 +636,7 @@ mmc_power_down(struct mmc_softc *sc) mmcbr_update_ios(dev); } +/* CMD7 */ static int mmc_select_card(struct mmc_softc *sc, uint16_t rca) { @@ -1042,6 +1079,7 @@ mmc_app_decode_sd_status(uint32_t *raw_sd_status, sd_status->erase_offset = mmc_get_bits(raw_sd_status, 512, 400, 2); } +/* CMD2 */ static int mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid) { @@ -1162,6 +1200,7 @@ mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp) return (err); } +/* CMD3 */ static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp) { @@ -1177,6 +1216,7 @@ mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp) return (err); } +/* CMD13 */ static int mmc_send_status(struct mmc_softc *sc, uint16_t rca, uint32_t *status) { @@ -1223,6 +1263,384 @@ mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard) ivar->read_only ? ", read-only" : ""); } +/* + * Enables the given function on SDIO card. + */ +static int +mmc_io_func_enable(struct mmc_softc *sc, uint32_t fn) +{ + int err, i; + uint8_t funcs; + + if (fn > sc->sdio_nfunc) { + device_printf(sc->dev, "Invalid function to enable: %d\n", fn); + return (MMC_ERR_INVALID); + } + + funcs = mmc_io_read_1(sc, 0, SD_IO_CCCR_FN_READY); + + funcs |= 1 << fn; + err = mmc_io_rw_direct(sc, 1, 0, SD_IO_CCCR_FN_ENABLE, &funcs); + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, "Error writing SDIO func enable %d\n", err); + return (err); + } + + funcs = 0; + for(i=0; i < 10; i++) { + funcs = mmc_io_read_1(sc, 0, SD_IO_CCCR_FN_READY); + + if (funcs & (1 << fn)) + return 0; + mmc_ms_delay(10); + } + + device_printf(sc->dev, "Cannot enable function %d!\n", fn); + return (MMC_ERR_FAILED); +} + +/* CMD52 */ +static int +mmc_io_rw_direct(struct mmc_softc *sc, int wr, uint32_t fn, uint32_t adr, + uint8_t *data) +{ + struct mmc_command cmd; + int err; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = SD_IO_RW_DIRECT; + cmd.arg = SD_IO_RW_FUNC(fn) | SD_IO_RW_ADR(adr); + if (wr) + cmd.arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data); + cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + cmd.data = NULL; + + err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + if (err) + return (err); + if (cmd.error) + return (cmd.error); + + if (cmd.resp[0] & R5_COM_CRC_ERROR) + return (MMC_ERR_BADCRC); + if (cmd.resp[0] & (R5_ILLEGAL_COMMAND | R5_FUNCTION_NUMBER)) + return (MMC_ERR_INVALID); + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return (MMC_ERR_FAILED); + + /* Just for information... */ + if (R5_IO_CURRENT_STATE(cmd.resp[0]) != 1) + printf("!!! SDIO state %d\n", R5_IO_CURRENT_STATE(cmd.resp[0])); + + if (cmd.resp[0] & R5_ERROR) + printf("An error was detected!\n"); + + if (cmd.resp[0] & R5_COM_CRC_ERROR) + printf("A CRC error was detected!\n"); + + *data = (uint8_t) (cmd.resp[0] & 0xff); + return (MMC_ERR_NONE); +} + +/* CMD53 */ +static int +mmc_io_rw_extended(struct mmc_softc *sc, int wr, uint32_t fn, uint32_t adr, + uint8_t *datap, size_t datalen, uint8_t incr, uint8_t blks) +{ + int err; + struct mmc_command cmd; + struct mmc_data data; + + memset(&cmd, 0, sizeof(cmd)); + memset(&data, 0, sizeof(data)); + memset(datap, 0, datalen); + + cmd.opcode = SD_IO_RW_EXTENDED; + cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + cmd.arg = SD_IO_RW_FUNC(fn); + cmd.arg |= SD_IO_RW_ADR(adr); + if (blks) + cmd.arg |= SD_IOE_RW_BLK | SD_IOE_RW_LEN(blks); + else + cmd.arg |= SD_IOE_RW_LEN(datalen); + if (wr) + cmd.arg |= SD_IO_RW_WR; + if (incr) + cmd.arg |= SD_IO_RW_INCR; + cmd.data = &data; + + data.data = datap; + data.len = datalen; + data.flags = wr ? MMC_DATA_WRITE : MMC_DATA_READ; + + err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + + if (err) + return (err); + if (cmd.error) + return (cmd.error); + + if (cmd.resp[0] & R5_COM_CRC_ERROR) + return (MMC_ERR_BADCRC); + if (cmd.resp[0] & (R5_ILLEGAL_COMMAND | R5_FUNCTION_NUMBER)) + return (MMC_ERR_INVALID); + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return (MMC_ERR_FAILED); + + return (MMC_ERR_NONE); +} + +static uint8_t +mmc_io_read_1(struct mmc_softc *sc, uint32_t fn, uint32_t adr) +{ + int err; + uint8_t val = 0; + + err = mmc_io_rw_direct(sc, 0, fn, adr, &val); + if (err) { + device_printf(sc->dev, "Err reading FN %d addr 0x%08X: %d", + fn, adr, err); + return (0xff); + } + return val; +} + +/* + * Parse Card Information Structure of the SDIO card. + * Both Function 0 CIS and Function 1-7 CIS are supported. + */ +static int +mmc_io_parse_cis(struct mmc_softc *sc, uint8_t func, uint32_t cisptr, struct sdio_function *sdio_func) +{ + uint32_t tmp; + + uint8_t tuple_id, tuple_len, func_id; + uint32_t addr, maninfo_p; + + char *cis1_info[4]; + int start, i, ch, count; + char cis1_info_buf[256]; + + sdio_func->number = func; + + cis1_info[0] = NULL; + cis1_info[1] = NULL; + cis1_info[2] = NULL; + cis1_info[3] = NULL; + memset(cis1_info_buf, 0, 256); + + tmp = 0; + addr = cisptr; + + /* + * XXX Some parts of this code are taken + * from sys/dev/pccard/pccard_cis.c. + * Need to think about making it more abstract. + */ + do { + tuple_id = mmc_io_read_1(sc, 0, addr++); + if (tuple_id == SD_IO_CISTPL_END) + break; + tuple_len = mmc_io_read_1(sc, 0, addr++); + if (tuple_len == 0 && tuple_id != 0x00) { + device_printf(sc->dev, + "Parse error: 0-length tuple %02X\n", tuple_id); + break; + } + + switch (tuple_id) { + case SD_IO_CISTPL_VERS_1: + maninfo_p = addr; + + sdio_func->cis1_major = mmc_io_read_1(sc, 0, maninfo_p); + sdio_func->cis1_minor = mmc_io_read_1(sc, 0, maninfo_p + 1); + + /* + * XXX Temp; use this to test if multi-byte read from + * cis1_info will also return crap + */ + sc->__sdio_cis1_info = maninfo_p + 2; + for (count = 0, start = 0, i = 0; + (count < 4) && ((i + 4) < 256); i++) { + ch = mmc_io_read_1(sc, 0, maninfo_p + 2 + i); + if (ch == 0xff) + break; + cis1_info_buf[i] = ch; + if (ch == 0) { + cis1_info[count] = + cis1_info_buf + start; + start = i + 1; + count++; + } + } + device_printf(sc->dev, "Read using 1-byte read:\n"); + hexdump(cis1_info_buf, 256, NULL, 0); + + device_printf(sc->dev, "*** Info[0]: %s\n", cis1_info[0]); + device_printf(sc->dev, "*** Info[1]: %s\n", cis1_info[1]); + device_printf(sc->dev, "*** Info[2]: %s\n", cis1_info[2]); + device_printf(sc->dev, "*** Info[3]: %s\n", cis1_info[3]); + break; + + case SD_IO_CISTPL_MANFID: + if (tuple_len < 4) { + device_printf(sc->dev, "MANFID is too short\n"); + break; + } + sdio_func->manufacturer = mmc_io_read_1(sc, 0, addr); + sdio_func->manufacturer |= mmc_io_read_1(sc, 0, addr + 1) << 8; + + sdio_func->product = mmc_io_read_1(sc, 0, addr + 2); + sdio_func->product |= mmc_io_read_1(sc, 0, addr + 3) << 8; + break; + + case SD_IO_CISTPL_FUNCID: + /* Function ID for SDIO devices is always 0x0C */ + if (tuple_len < 1) { + device_printf(sc->dev, "FUNCID is too short\n"); + break; + } + func_id = mmc_io_read_1(sc, 0, addr); + if (func_id != 0x0C) + device_printf(sc->dev, "func_id non-std: %d\n", func_id); + break; + + case SD_IO_CISTPL_FUNCE: + if (tuple_len < 4) { + device_printf(sc->dev, "FUNCE is too short\n"); + break; + } + uint8_t ext_data_type = mmc_io_read_1(sc, 0, addr); + + if (func == 0) { + if (ext_data_type != 0x0) + device_printf(sc->dev, + "funce for func 0 non-std: %d\n", + ext_data_type); + sdio_func->max_blksize = + mmc_io_read_1(sc, 0, addr + 1); + sdio_func->max_blksize |= + mmc_io_read_1(sc, 0, addr + 2) << 8; + sdio_func->max_tran_speed = + mmc_io_read_1(sc, 0, addr + 3); + uint8_t max_tran_rate = + sdio_func->max_tran_speed & 0x7; + uint8_t timecode = + (sdio_func->max_tran_speed >> 3) & 0xF; + + device_printf(sc->dev, + "*** Max tran speed: %02X (unit %d, time value code %d\n", + sdio_func->max_tran_speed, max_tran_rate, timecode); + } else { + if (ext_data_type != 0x1) + device_printf(sc->dev, + "funce for func 0 non-std: %d\n", + ext_data_type); + sdio_func->max_blksize = + mmc_io_read_1(sc, 0, addr + 0x0c); + sdio_func->max_blksize |= + mmc_io_read_1(sc, 0, addr + 0x0d) << 8; + + } + + break; + + default: + device_printf(sc->dev, + "*** Skipping tuple ID %02X len %02X\n", + tuple_id, tuple_len); + break; + } + + addr += tuple_len; + tmp++; + } while (tuple_id != SD_IO_CISTPL_END && tmp < 10); + + return 0; +} + +/* + * Parse Card Common Control Register of the SDIO card + */ +static int +mmc_io_parse_cccr(struct mmc_softc *sc) +{ + uint32_t cisptr = 0; + + cisptr = mmc_io_read_1(sc, 0, SD_IO_CCCR_CISPTR); + cisptr |= mmc_io_read_1(sc, 0, SD_IO_CCCR_CISPTR + 1) << 8; + cisptr |= mmc_io_read_1(sc, 0, SD_IO_CCCR_CISPTR + 2) << 16; + + if (cisptr < SD_IO_CIS_START || + cisptr > SD_IO_CIS_START + SD_IO_CIS_SIZE) { + device_printf(sc->dev, "Bad CIS pointer in CCCR: %08X\n", cisptr); + return (-1); + } + + return mmc_io_parse_cis(sc, 0, cisptr, &sc->sdio_func0); +} + +/* + * Parse Function Basic Register of the given function + */ +static int +mmc_io_parse_fbr(struct mmc_softc *sc, uint8_t func) +{ + uint32_t fbr_addr, cisptr; + + fbr_addr = SD_IO_FBR_START * func + 0x9; + cisptr = mmc_io_read_1(sc, 0, fbr_addr); + cisptr |= mmc_io_read_1(sc, 0, fbr_addr + 1) << 8; + cisptr |= mmc_io_read_1(sc, 0, fbr_addr + 2) << 16; + + if (cisptr < SD_IO_CIS_START || + cisptr > SD_IO_CIS_START + SD_IO_CIS_SIZE) { + device_printf(sc->dev, "Bad CIS pointer in FBR: %08X\n", cisptr); + return (-1); + } + + struct sdio_function *f = malloc(sizeof(struct sdio_function), M_DEVBUF, M_WAITOK); + STAILQ_INSERT_TAIL(&sc->sdiof_head, f, sdiof_list); + + return mmc_io_parse_cis(sc, func, cisptr, f); +} + +static void +mmc_io_get_info(struct mmc_softc *sc) +{ + sc->sdio_bus_width = bus_width_1; + sc->sdio_support_hs = 0; + + uint8_t cardcap = mmc_io_read_1(sc, 0, SD_IO_CCCR_CARDCAP); + uint8_t hs_info = mmc_io_read_1(sc, 0, SD_IO_CCCR_CISPTR + 0x13); + + /* + * If the card is a full-speed card, it supports 4-bit bus width. + * If it is low-speed, we check 4BLS to determine if it + * supports 4-bit width + */ + if (((cardcap & (1 << 6)) && (cardcap & (1 << 7))) || + ((cardcap & (1 << 6)) == 0)) + sc->sdio_bus_width = bus_width_4; + + sc->sdio_support_hs = hs_info & (1 << 0); +} + +/* Set bus width for SDIO card */ +static int +mmc_io_set_bus_width(struct mmc_softc *sc, int width) +{ + uint8_t busctrl = mmc_io_read_1(sc, 0, SD_IO_CCCR_BUS_WIDTH); + + busctrl |= width == bus_width_4 ? CCCR_BUS_WIDTH_4 : 0; + + if (mmc_debug) + device_printf(sc->dev, "Setting SDIO bus width to %d bits\n", + width == bus_width_4 ? 4 : 1); + + return mmc_io_rw_direct(sc, 1, 0, SD_IO_CCCR_BUS_WIDTH, &busctrl); +} + static void mmc_discover_cards(struct mmc_softc *sc) { @@ -1233,11 +1651,87 @@ mmc_discover_cards(struct mmc_softc *sc) device_t child; uint16_t rca = 2; u_char switch_res[64]; + uint8_t nfunc, mem_present; if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing cards\n"); while (1) { - err = mmc_all_send_cid(sc, raw_cid); + /* + * Probe SDIO first, because SDIO cards don't have + * a CID register and won't respond to the CMD2 + */ + mmc_idle_cards(sc); + err = mmc_probe_sdio(sc, 0, NULL, &nfunc, &mem_present); + sc->sdio_nfunc = nfunc; + if (err != MMC_ERR_NONE && err != MMC_ERR_TIMEOUT) { + device_printf(sc->dev, "Error probing SDIO %d\n", err); + break; + } + + /* The card answered OK -> SDIO */ + if (err == MMC_ERR_NONE) { + device_printf(sc->dev, "Detected SDIO card\n"); + mmc_send_relative_addr(sc, &resp); /* CMD3 */ + uint16_t rca = resp >> 16; + err = mmc_select_card(sc, rca); /* CMD7 */ + sc->__sdio_rca = rca; /* XXX Temp; for testing only */ + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, "Error selecting SDIO %d\n", err); + break; + } + + device_printf(sc->dev, "Get card info\n"); + mmc_io_parse_cccr(sc); + mmc_io_get_info(sc); + for(i=1; i <= nfunc; i++) { + device_printf(sc->dev, + "Get info for function %d\n", i); + mmc_io_parse_fbr(sc, i); + mmc_io_func_enable(sc, i); + } + + device_printf(sc->dev, "=== Functions ===\n"); + struct sdio_function *f; + + STAILQ_FOREACH(f, &sc->sdiof_head, sdiof_list) + device_printf(sc->dev, + "FN %d, vendor %04X, product %04X; blksize %02X\n", + f->number, f->manufacturer, f->product, f->max_blksize); + + /* + * Only set 4-bit width if both the host and the card + * support it. + * The card starts in 1-bit mode by default. + */ + if (mmcbr_get_caps(sc->dev) & MMC_CAP_4_BIT_DATA && + sc->sdio_bus_width == bus_width_4) { + mmc_io_set_bus_width(sc, sc->sdio_bus_width); + mmcbr_set_bus_width(sc->dev, sc->sdio_bus_width); + } + + /* Set high speed mode if host and card support it */ + if (mmcbr_get_caps(sc->dev) & MMC_CAP_HSPEED && + sc->sdio_support_hs) { + device_printf(sc->dev, "Activating high-speed mode"); + uint8_t hs_info = 1; + err = mmc_io_rw_direct(sc, 1, 0, + SD_IO_CCCR_CISPTR + 0x13, &hs_info); + if (err != MMC_ERR_NONE) { + device_printf(sc->dev, "Error setting HS mode%d\n", err); + return; + } + sc->sdio_timing = bus_timing_hs; + sc->sdio_tran_speed = 50 * 1000 * 1000; + } else { + sc->sdio_tran_speed = 25 * 1000 * 1000; + sc->sdio_timing = bus_timing_normal; + } + + if (!mem_present) + return; + } + + err = mmc_all_send_cid(sc, raw_cid); /* Command 2 */ if (err == MMC_ERR_TIMEOUT) break; if (err != MMC_ERR_NONE) { @@ -1491,9 +1985,45 @@ mmc_delete_cards(struct mmc_softc *sc) return (0); } +/* CMD 5 */ +static int +mmc_probe_sdio(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr, uint8_t *nfunc, uint8_t *mem_present) { + struct mmc_command cmd; + int err = MMC_ERR_NONE, i; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = IO_SEND_OP_COND; + cmd.arg = 0; + cmd.flags = MMC_RSP_R4; + cmd.data = NULL; + + for (i = 0; i < 1000; i++) { + err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) + break; + if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) || + (ocr & MMC_OCR_VOLTAGE) == 0) + break; + err = MMC_ERR_TIMEOUT; + mmc_ms_delay(10); + } + + if (err == MMC_ERR_NONE) { + if (rocr) + *rocr = cmd.resp[0]; + if (nfunc) + *nfunc = SD_IO_OCR_NUM_FUNCTIONS(cmd.resp[0]); + if (mem_present) + *mem_present = cmd.resp[0] >> 27 & 0x1; + } + + return (err); +} + static void mmc_go_discovery(struct mmc_softc *sc) { + uint8_t nfunc, mem_present; uint32_t ocr; device_t dev; int err; @@ -1509,17 +2039,24 @@ mmc_go_discovery(struct mmc_softc *sc) if (bootverbose || mmc_debug) device_printf(sc->dev, "Probing bus\n"); mmc_idle_cards(sc); - err = mmc_send_if_cond(sc, 1); + err = mmc_send_if_cond(sc, 1); /* SD_SEND_IF_COND = 8 */ if ((bootverbose || mmc_debug) && err == 0) device_printf(sc->dev, "SD 2.0 interface conditions: OK\n"); - if (mmc_send_app_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { + if (mmc_probe_sdio(sc, 0, &ocr, &nfunc, &mem_present) == MMC_ERR_NONE) { + device_printf(dev, "SDIO probe OK (OCR: 0x%08x, %d functions, memory: %d)\n", ocr, nfunc, mem_present); + if (nfunc > 0 && mem_present) { + device_printf(sc->dev, "SDIO combo cards are not supported yet"); + return; + } + } else + if (mmc_send_app_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { /* retry 55 -> then 41 */ if (bootverbose || mmc_debug) device_printf(sc->dev, "SD probe: failed\n"); /* * Failed, try MMC */ mmcbr_set_mode(dev, mode_mmc); - if (mmc_send_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { + if (mmc_send_op_cond(sc, 0, &ocr) != MMC_ERR_NONE) { /* command 1 */ if (bootverbose || mmc_debug) device_printf(sc->dev, "MMC probe: failed\n"); ocr = 0; /* Failed both, powerdown. */ @@ -1553,9 +2090,11 @@ mmc_go_discovery(struct mmc_softc *sc) * Reselect the cards after we've idled them above. */ if (mmcbr_get_mode(dev) == mode_sd) { - err = mmc_send_if_cond(sc, 1); - mmc_send_app_op_cond(sc, - (err ? 0 : MMC_OCR_CCS) | mmcbr_get_ocr(dev), NULL); + if (mem_present) { + err = mmc_send_if_cond(sc, 1); /* CMD 8 */ + mmc_send_app_op_cond(sc, /* 41 -> 55 */ + (err ? 0 : MMC_OCR_CCS) | mmcbr_get_ocr(dev), NULL); + } } else mmc_send_op_cond(sc, mmcbr_get_ocr(dev), NULL); mmc_discover_cards(sc); @@ -1564,6 +2103,24 @@ mmc_go_discovery(struct mmc_softc *sc) mmcbr_set_bus_mode(dev, pushpull); mmcbr_update_ios(dev); mmc_calculate_clock(sc); + + /* XXX TESTING RW_EXTENDED */ + mmc_select_card(sc, sc->__sdio_rca); + + /* Try to do normal CMD52 that should work correctly */ + uint8_t hs_info; + err = mmc_io_rw_direct(sc, 0, 0, SD_IO_CCCR_CISPTR + 0x13, &hs_info); + if (err) + device_printf(sc->dev, "HS INFO read err %d\n", err); + + /* Now try actual command */ + mmc_debug = 10; + uint8_t data[100]; + err = mmc_io_rw_extended(sc, 0, 0, sc->__sdio_cis1_info, data, 100, 0, 0); + if (err) + device_printf(sc->dev, "Ext read err %d\n", err); + hexdump(data, 100, NULL, 0); + bus_generic_attach(dev); /* mmc_update_children_sysctl(dev);*/ } @@ -1575,7 +2132,7 @@ mmc_calculate_clock(struct mmc_softc *sc) int nkid, i, f_min, f_max; device_t *kids; struct mmc_ivars *ivar; - + f_min = mmcbr_get_f_min(sc->dev); f_max = mmcbr_get_f_max(sc->dev); max_dtr = max_hs_dtr = f_max; @@ -1583,6 +2140,12 @@ mmc_calculate_clock(struct mmc_softc *sc) max_timing = bus_timing_hs; else max_timing = bus_timing_normal; + + if (sc->sdio_timing < max_timing) + max_timing = sc->sdio_timing; + if (sc->sdio_tran_speed < max_dtr) + max_dtr = sc->sdio_tran_speed; + if (device_get_children(sc->dev, &kids, &nkid) != 0) panic("can't get children"); for (i = 0; i < nkid; i++) { @@ -1735,3 +2298,4 @@ DRIVER_MODULE(mmc, at91_mci, mmc_driver, mmc_devclass, NULL, NULL); DRIVER_MODULE(mmc, sdhci_pci, mmc_driver, mmc_devclass, NULL, NULL); DRIVER_MODULE(mmc, sdhci_bcm, mmc_driver, mmc_devclass, NULL, NULL); DRIVER_MODULE(mmc, sdhci_fdt, mmc_driver, mmc_devclass, NULL, NULL); +DRIVER_MODULE(mmc, sdio, mmc_driver, mmc_devclass, NULL, NULL); diff --git a/sys/dev/mmc/mmcioreg.h b/sys/dev/mmc/mmcioreg.h new file mode 100644 index 0000000..10e304b --- /dev/null +++ b/sys/dev/mmc/mmcioreg.h @@ -0,0 +1,96 @@ +/* $OpenBSD: sdmmc_ioreg.h,v 1.4 2007/06/02 01:48:37 uwe Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (c) 2006 Uwe Stuehler + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SDMMC_IOREG_H +#define _SDMMC_IOREG_H + +/* SDIO commands */ /* response type */ +#define SD_IO_SEND_OP_COND 5 /* R4 */ +#define SD_IO_RW_DIRECT 52 /* R5 */ +#define SD_IO_RW_EXTENDED 53 /* R5? */ + +/* CMD52 arguments */ +#define SD_ARG_CMD52_READ (0<<31) +#define SD_ARG_CMD52_WRITE (1<<31) +#define SD_ARG_CMD52_FUNC_SHIFT 28 +#define SD_ARG_CMD52_FUNC_MASK 0x7 +#define SD_ARG_CMD52_EXCHANGE (1<<27) +#define SD_ARG_CMD52_REG_SHIFT 9 +#define SD_ARG_CMD52_REG_MASK 0x1ffff +#define SD_ARG_CMD52_DATA_SHIFT 0 +#define SD_ARG_CMD52_DATA_MASK 0xff +#define SD_R5_DATA(resp) ((resp)[0] & 0xff) + +/* CMD53 arguments */ +#define SD_ARG_CMD53_READ (0<<31) +#define SD_ARG_CMD53_WRITE (1<<31) +#define SD_ARG_CMD53_FUNC_SHIFT 28 +#define SD_ARG_CMD53_FUNC_MASK 0x7 +#define SD_ARG_CMD53_BLOCK_MODE (1<<27) +#define SD_ARG_CMD53_INCREMENT (1<<26) +#define SD_ARG_CMD53_REG_SHIFT 9 +#define SD_ARG_CMD53_REG_MASK 0x1ffff +#define SD_ARG_CMD53_LENGTH_SHIFT 0 +#define SD_ARG_CMD53_LENGTH_MASK 0x1ff +#define SD_ARG_CMD53_LENGTH_MAX 64 /* XXX should be 511? */ + +/* 48-bit response decoding (32 bits w/o CRC) */ +#define MMC_R4(resp) ((resp)[0]) +#define MMC_R5(resp) ((resp)[0]) + +/* SD R4 response (IO OCR) */ +#define SD_IO_OCR_MEM_READY (1<<31) +#define SD_IO_OCR_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x3) +/* XXX big fat memory present "flag" because we don't know better */ +#define SD_IO_OCR_MEM_PRESENT (0xf<<24) +#define SD_IO_OCR_MASK 0x00fffff0 + +/* Card Common Control Registers (CCCR) */ +#define SD_IO_CCCR_START 0x00000 +#define SD_IO_CCCR_SIZE 0x100 +#define SD_IO_CCCR_FN_ENABLE 0x02 +#define SD_IO_CCCR_FN_READY 0x03 +#define SD_IO_CCCR_INT_ENABLE 0x04 +#define SD_IO_CCCR_CTL 0x06 +#define CCCR_CTL_RES (1<<3) +#define SD_IO_CCCR_BUS_WIDTH 0x07 +#define CCCR_BUS_WIDTH_4 (1<<1) +#define CCCR_BUS_WIDTH_1 (1<<0) +#define SD_IO_CCCR_CARDCAP 0x08 +#define SD_IO_CCCR_CISPTR 0x09 /* XXX 9-10, 10-11, or 9-12 */ + +/* Function Basic Registers (FBR) */ +#define SD_IO_FBR_START 0x00100 +#define SD_IO_FBR_SIZE 0x00700 + +/* Card Information Structure (CIS) */ +#define SD_IO_CIS_START 0x01000 +#define SD_IO_CIS_SIZE 0x17000 + +/* CIS tuple codes (based on PC Card 16) */ +#define SD_IO_CISTPL_VERS_1 0x15 +#define SD_IO_CISTPL_MANFID 0x20 +#define SD_IO_CISTPL_FUNCID 0x21 +#define SD_IO_CISTPL_FUNCE 0x22 +#define SD_IO_CISTPL_END 0xff + +/* CISTPL_FUNCID codes */ +/* OpenBSD incorrectly defines 0x0c as FUNCTION_WLAN */ +/* #define SDMMC_FUNCTION_WLAN 0x0c */ +#endif diff --git a/sys/dev/mmc/mmcreg.h b/sys/dev/mmc/mmcreg.h index f454ddb..4b65d91 100644 --- a/sys/dev/mmc/mmcreg.h +++ b/sys/dev/mmc/mmcreg.h @@ -85,6 +85,8 @@ struct mmc_command { #define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY) #define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_PRESENT) +#define MMC_RSP_R4 (MMC_RSP_PRESENT) +#define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC) #define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC) #define MMC_RSP(x) ((x) & MMC_RSP_MASK) @@ -151,6 +153,30 @@ struct mmc_command { #define R1_STATE_PRG 7 #define R1_STATE_DIS 8 +/* + * R5 responses + * + * Types (per SD 2.0 standard) + *e : error bit + *s : status bit + *r : detected and set for the actual command response + *x : Detected and set during command execution. The host can get + * the status by issuing a command with R1 response. + * + * Clear Condition (per SD 2.0 standard) + *a : according to the card current state. + *b : always related to the previous command. reception of a valid + * command will clear it (with a delay of one command). + *c : clear by read + */ +#define R5_COM_CRC_ERROR (1u << 15)/* er, b */ +#define R5_ILLEGAL_COMMAND (1u << 14)/* er, b */ +#define R5_IO_CURRENT_STATE_MASK (3u << 12)/* s, b */ +#define R5_IO_CURRENT_STATE(x) (((x) & R5_IO_CURRENT_STATE_MASK) >> 12) +#define R5_ERROR (1u << 11)/* erx, c */ +#define R5_FUNCTION_NUMBER (1u << 9)/* er, c */ +#define R5_OUT_OF_RANGE (1u << 8)/* er, c */ + struct mmc_data { size_t len; /* size of the data */ size_t xfer_len; @@ -181,7 +207,7 @@ struct mmc_request { #define MMC_SET_RELATIVE_ADDR 3 #define SD_SEND_RELATIVE_ADDR 3 #define MMC_SET_DSR 4 - /* reserved: 5 */ +#define IO_SEND_OP_COND 5 #define MMC_SWITCH_FUNC 6 #define MMC_SWITCH_FUNC_CMDS 0 #define MMC_SWITCH_FUNC_SET 1 @@ -335,6 +361,20 @@ struct mmc_request { #define SD_MAX_HS 50000000 +/* + * SDIO Direct & Extended I/O + */ +#define SD_IO_RW_WR (1u << 31) +#define SD_IO_RW_FUNC(x) (((x) & 0x7) << 28) +#define SD_IO_RW_RAW (1u << 27) +#define SD_IO_RW_INCR (1u << 26) +#define SD_IO_RW_ADR(x) (((x) & 0x1FFFF) << 9) +#define SD_IO_RW_DAT(x) (((x) & 0xFF) << 0) +#define SD_IO_RW_LEN(x) (((x) & 0xFF) << 0) + +#define SD_IOE_RW_LEN(x) (((x) & 0x1FF) << 0) +#define SD_IOE_RW_BLK (1u << 27) + /* OCR bits */ /* From owner-freebsd-embedded@FreeBSD.ORG Thu Jul 4 05:53:45 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 59ECDC21 for ; Thu, 4 Jul 2013 05:53:45 +0000 (UTC) (envelope-from freebsd_arm@myspectrum.nl) Received: from mail.virtualhost.nl (mail.virtualhost.nl [89.200.201.133]) by mx1.freebsd.org (Postfix) with ESMTP id A8EC61F99 for ; Thu, 4 Jul 2013 05:53:43 +0000 (UTC) Received: (qmail 94225 invoked by uid 1141); 4 Jul 2013 07:46:54 +0200 Received: from ip120-12-208-87.adsl2.static.versatel.nl (HELO [10.0.0.15]) (87.208.12.120) (smtp-auth username freebsd_arm@myspectrum.nl, mechanism plain) by mail.virtualhost.nl (qpsmtpd/0.84) with (CAMELLIA256-SHA encrypted) ESMTPSA; Thu, 04 Jul 2013 07:46:54 +0200 Message-ID: <51D50C55.1040300@myspectrum.nl> Date: Thu, 04 Jul 2013 07:47:01 +0200 From: Jeroen Hofstee User-Agent: Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130623 Thunderbird/17.0.7 MIME-Version: 1.0 To: Ilya Bakulin Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> <51D3282C.1090701@bakulin.de> <20130703222002.GA60491@olymp.kibab.com> In-Reply-To: <20130703222002.GA60491@olymp.kibab.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: Alexander Motin , freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2013 05:53:45 -0000 Hello Ilya, On 07/04/2013 12:20 AM, Ilya Bakulin wrote: > So some bytes lack 0x40... This problem occurs also with other numbers > read from the card, for example, vendor ID is read as 0x029F instead of 0x02DF. > +/* Halfword bit masks used for command response extraction. */ > +#define MV_SDIO_RSP48_BM2 0x0002 /* Lower 2 bits. */ > +#define MV_SDIO_RSP48_BM6 0x003f /* Lower 6 bits. */ > + /* Response bits [15:14] and [13:8] */ > + *rp++ = (resp[2] & MV_SDIO_RSP48_BM6) | > + ((word & MV_SDIO_RSP48_BM2) << 6); > + From the looks if it, MV_SDIO_RSP48_BM2 must be 3 instead 2. Regards, Jeroen From owner-freebsd-embedded@FreeBSD.ORG Thu Jul 4 08:26:52 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 7B6F336B; Thu, 4 Jul 2013 08:26:52 +0000 (UTC) (envelope-from ilya@bakulin.de) Received: from olymp.kibab.com (olymp.kibab.com [5.9.14.202]) by mx1.freebsd.org (Postfix) with ESMTP id 3E20016EE; Thu, 4 Jul 2013 08:26:51 +0000 (UTC) X-DKIM: OpenDKIM Filter v2.5.2 olymp.kibab.com C03B33F47A DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=bakulin.de; s=default; t=1372926410; bh=GGeGsLeMl9ppbB3rw7iKbFguKsL9cKCDnXZ4EYF1W1U=; h=Date:From:To:CC:Subject:References:In-Reply-To; b=krHz8/O50hoPUs7Q/EnO6ZD3SFmS4/BoHZYr682rQ4ejpSi7ygo4sQXXMBaf9Fwp9 1koOO3qd6KA4URmNtCLASjDlZjFvyCl8ufgZ3WgFf6P9L5pFvqbxg0VD2sfkNjx7hW 388dTdaI5KKT7rFJRvcnRnGMndKuXHR9fPTt16rQ= Message-ID: <51D531CB.3060300@bakulin.de> Date: Thu, 04 Jul 2013 10:26:51 +0200 From: Ilya Bakulin MIME-Version: 1.0 To: Jeroen Hofstee Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> <51D3282C.1090701@bakulin.de> <20130703222002.GA60491@olymp.kibab.com> <51D50C55.1040300@myspectrum.nl> In-Reply-To: <51D50C55.1040300@myspectrum.nl> X-Enigmail-Version: 1.5.1 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Cc: Alexander Motin , freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2013 08:26:52 -0000 Hi Jeroen, On 04.07.13 07:47, Jeroen Hofstee wrote: > From the looks if it, MV_SDIO_RSP48_BM2 must be 3 instead 2. Wonderful, it works now. Thanks for the fix!!! By the way, I keep my changes in the Git repository here: https://github.com/kibab/freebsd/commits/kibab-dplug -- Regards, Ilya Bakulin From owner-freebsd-embedded@FreeBSD.ORG Thu Jul 4 16:09:13 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id CE007923 for ; Thu, 4 Jul 2013 16:09:13 +0000 (UTC) (envelope-from imp@bsdimp.com) Received: from mail-ie0-f173.google.com (mail-ie0-f173.google.com [209.85.223.173]) by mx1.freebsd.org (Postfix) with ESMTP id 9D6171EF8 for ; Thu, 4 Jul 2013 16:09:13 +0000 (UTC) Received: by mail-ie0-f173.google.com with SMTP id k13so3474202iea.18 for ; Thu, 04 Jul 2013 09:09:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=sender:subject:mime-version:content-type:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to:x-mailer :x-gm-message-state; bh=RgpZsC7tmNHq59IEg2L1sqyoJPtU9EX/4v1I6TXxe+s=; b=bSI7iaAKfogdxQPFVQWl661OWIwBzZt7Wq2XxfzfqYm6Lj41oltTg1/WLVPGnXcCmW FeEPAA5oeLxNsT30Iu8cnokISquY4Dsjp0WaYL0Q1TOEkQZDeocZiWi/Uw+mHi8puu2b TBP372fgjc7tiIY9Z60YhsgDwwztJBhMCPh/QZhikLMbBoF7XpiYX8pXk+TiurPtU/87 ZjlQLEuY6f6recN4GEWJlP8fiPYjoaT1PCz06sjy4XThyErsus5EtdGaqe34to/zYcgQ TH/o7gX732tvQaGzTdCRpLbN9yx1SEh5Tl0zmnfFi4uXPNoTkxqsPBIL00Y0iiGdLQrq 03dg== X-Received: by 10.50.130.113 with SMTP id od17mr3173139igb.10.1372954152980; Thu, 04 Jul 2013 09:09:12 -0700 (PDT) Received: from 53.imp.bsdimp.com (50-78-194-198-static.hfc.comcastbusiness.net. [50.78.194.198]) by mx.google.com with ESMTPSA id hj6sm27795475igb.1.2013.07.04.09.09.11 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 04 Jul 2013 09:09:11 -0700 (PDT) Sender: Warner Losh Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug Mime-Version: 1.0 (Apple Message framework v1085) Content-Type: text/plain; charset=us-ascii From: Warner Losh In-Reply-To: <51D50C55.1040300@myspectrum.nl> Date: Thu, 4 Jul 2013 10:09:09 -0600 Content-Transfer-Encoding: quoted-printable Message-Id: <16DEBC38-F99A-4733-86FD-9E81A146CE5C@bsdimp.com> References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> <51D3282C.1090701@bakulin.de> <20130703222002.GA60491@olymp.kibab.com> <51D50C55.1040300@myspectrum.nl> To: Jeroen Hofstee X-Mailer: Apple Mail (2.1085) X-Gm-Message-State: ALoCoQnO6PcuAfnOEhDj5WIFU9ajhFq6x6eDxp5zv6aN7KdNSuAmq/umVRIaEQWm66cCuZVCIi+N Cc: Alexander Motin , Ilya Bakulin , freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2013 16:09:13 -0000 On Jul 3, 2013, at 11:47 PM, Jeroen Hofstee wrote: > Hello Ilya, >=20 > On 07/04/2013 12:20 AM, Ilya Bakulin wrote: >> So some bytes lack 0x40... This problem occurs also with other = numbers >> read from the card, for example, vendor ID is read as 0x029F instead = of 0x02DF. >=20 >> +/* Halfword bit masks used for command response extraction. */ >> +#define MV_SDIO_RSP48_BM2 0x0002 /* Lower 2 bits. */ >> +#define MV_SDIO_RSP48_BM6 0x003f /* Lower 6 bits. */ >=20 >> + /* Response bits [15:14] and [13:8] */ >> + *rp++ =3D (resp[2] & MV_SDIO_RSP48_BM6) | >> + ((word & MV_SDIO_RSP48_BM2) << 6); >> + >=20 > =46rom the looks if it, MV_SDIO_RSP48_BM2 must be 3 instead 2. And 0x0031 doesn't look right either... I'd have expected 0x3f. Warner From owner-freebsd-embedded@FreeBSD.ORG Thu Jul 4 17:42:51 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id A3369298 for ; Thu, 4 Jul 2013 17:42:51 +0000 (UTC) (envelope-from freebsd_arm@myspectrum.nl) Received: from mail.virtualhost.nl (mail.virtualhost.nl [89.200.201.133]) by mx1.freebsd.org (Postfix) with ESMTP id F1AE01362 for ; Thu, 4 Jul 2013 17:42:50 +0000 (UTC) Received: (qmail 67420 invoked by uid 1141); 4 Jul 2013 19:42:42 +0200 Received: from ip120-12-208-87.adsl2.static.versatel.nl (HELO [10.0.0.15]) (87.208.12.120) (smtp-auth username freebsd_arm@myspectrum.nl, mechanism plain) by mail.virtualhost.nl (qpsmtpd/0.84) with (CAMELLIA256-SHA encrypted) ESMTPSA; Thu, 04 Jul 2013 19:42:42 +0200 Message-ID: <51D5B41A.5000805@myspectrum.nl> Date: Thu, 04 Jul 2013 19:42:50 +0200 From: Jeroen Hofstee User-Agent: Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130623 Thunderbird/17.0.7 MIME-Version: 1.0 To: Warner Losh Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> <51D3282C.1090701@bakulin.de> <20130703222002.GA60491@olymp.kibab.com> <51D50C55.1040300@myspectrum.nl> <16DEBC38-F99A-4733-86FD-9E81A146CE5C@bsdimp.com> In-Reply-To: <16DEBC38-F99A-4733-86FD-9E81A146CE5C@bsdimp.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: Alexander Motin , Ilya Bakulin , freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2013 17:42:51 -0000 Hello Warner, On 07/04/2013 06:09 PM, Warner Losh wrote: > On Jul 3, 2013, at 11:47 PM, Jeroen Hofstee wrote: > >> Hello Ilya, >> >> On 07/04/2013 12:20 AM, Ilya Bakulin wrote: >>> So some bytes lack 0x40... This problem occurs also with other numbers >>> read from the card, for example, vendor ID is read as 0x029F instead of 0x02DF. >>> +/* Halfword bit masks used for command response extraction. */ >>> +#define MV_SDIO_RSP48_BM2 0x0002 /* Lower 2 bits. */ >>> +#define MV_SDIO_RSP48_BM6 0x003f /* Lower 6 bits. */ >>> + /* Response bits [15:14] and [13:8] */ >>> + *rp++ = (resp[2] & MV_SDIO_RSP48_BM6) | >>> + ((word & MV_SDIO_RSP48_BM2) << 6); >>> + >> From the looks if it, MV_SDIO_RSP48_BM2 must be 3 instead 2. > And 0x0031 doesn't look right either... I'd have expected 0x3f. which 0x0031 (perhaps I need to have my eyes checked....)? Regards, Jeroen From owner-freebsd-embedded@FreeBSD.ORG Thu Jul 4 19:42:18 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id C48CF5EA for ; Thu, 4 Jul 2013 19:42:18 +0000 (UTC) (envelope-from imp@bsdimp.com) Received: from mail-ie0-f180.google.com (mail-ie0-f180.google.com [209.85.223.180]) by mx1.freebsd.org (Postfix) with ESMTP id 943DD1BA8 for ; Thu, 4 Jul 2013 19:42:18 +0000 (UTC) Received: by mail-ie0-f180.google.com with SMTP id f4so3662476iea.25 for ; Thu, 04 Jul 2013 12:42:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=sender:subject:mime-version:content-type:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to:x-mailer :x-gm-message-state; bh=4efWXdI2sx2fWL/knga7F455OElbR25vdNwfTm1jv1c=; b=fivMj+EFmkoau7wDgxmciwwFyB4O/ntR6eypNBmVdIeDs2MytRkXEVichg2AXm58IE P8/JVDjxowEaCKgWJdoi8nFBrCittcTub6/CK7A523ehPz02jtYr4CHD46dT6CO86zkr ym/tOH8CvDGCeCohhlRWqFdfvPRA0zaZRgU1H1tkt/rqe1ThddcvSUcIcTMJPd9GmD2g BWaxSkNCTqPrJiDnwMqY/Bgb21bXgI5UBoFNXtD/g62jpGWLwW/M1rMj7pMfQ+Hcr11w TCJ09fh3mFlEF9xPTDqivgSCdt2pzjoqbwPLz39laGQQhg9KEo5dp+xSOWBOqYKGXpPK jPKw== X-Received: by 10.50.127.139 with SMTP id ng11mr17110919igb.6.1372966932697; Thu, 04 Jul 2013 12:42:12 -0700 (PDT) Received: from 53.imp.bsdimp.com (50-78-194-198-static.hfc.comcastbusiness.net. [50.78.194.198]) by mx.google.com with ESMTPSA id x10sm28088806igl.3.2013.07.04.12.42.10 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 04 Jul 2013 12:42:11 -0700 (PDT) Sender: Warner Losh Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug Mime-Version: 1.0 (Apple Message framework v1085) Content-Type: text/plain; charset=us-ascii From: Warner Losh In-Reply-To: <51D5B41A.5000805@myspectrum.nl> Date: Thu, 4 Jul 2013 13:42:09 -0600 Content-Transfer-Encoding: quoted-printable Message-Id: References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> <51D3282C.1090701@bakulin.de> <20130703222002.GA60491@olymp.kibab.com> <51D50C55.1040300@myspectrum.nl> <16DEBC38-F99A-4733-86FD-9E81A146CE5C@bsdimp.com> <51D5B41A.5000805@myspectrum.nl> To: Jeroen Hofstee X-Mailer: Apple Mail (2.1085) X-Gm-Message-State: ALoCoQl3sZDCkCLrmi669yxnmXeP2v8KZ9Upy2I9HlMqSdMr68RBJ1N0KuNckguENxJalSDU2P4O Cc: Alexander Motin , Ilya Bakulin , freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2013 19:42:18 -0000 On Jul 4, 2013, at 11:42 AM, Jeroen Hofstee wrote: > Hello Warner, >=20 > On 07/04/2013 06:09 PM, Warner Losh wrote: >> On Jul 3, 2013, at 11:47 PM, Jeroen Hofstee wrote: >>=20 >>> Hello Ilya, >>>=20 >>> On 07/04/2013 12:20 AM, Ilya Bakulin wrote: >>>> So some bytes lack 0x40... This problem occurs also with other = numbers >>>> read from the card, for example, vendor ID is read as 0x029F = instead of 0x02DF. >>>> +/* Halfword bit masks used for command response extraction. */ >>>> +#define MV_SDIO_RSP48_BM2 0x0002 /* Lower 2 bits. */ >>>> +#define MV_SDIO_RSP48_BM6 0x003f /* Lower 6 bits. */ >>>> + /* Response bits [15:14] and [13:8] */ >>>> + *rp++ =3D (resp[2] & MV_SDIO_RSP48_BM6) | >>>> + ((word & MV_SDIO_RSP48_BM2) << 6); >>>> + >>> =46rom the looks if it, MV_SDIO_RSP48_BM2 must be 3 instead 2. >> And 0x0031 doesn't look right either... I'd have expected 0x3f. > which 0x0031 (perhaps I need to have my eyes checked....)? No, my eyes. Warner From owner-freebsd-embedded@FreeBSD.ORG Thu Jul 4 22:59:39 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 3CFB7D12; Thu, 4 Jul 2013 22:59:39 +0000 (UTC) (envelope-from ilya@bakulin.de) Received: from olymp.kibab.com (olymp.kibab.com [5.9.14.202]) by mx1.freebsd.org (Postfix) with ESMTP id EE0DB12DF; Thu, 4 Jul 2013 22:59:38 +0000 (UTC) X-DKIM: OpenDKIM Filter v2.5.2 olymp.kibab.com 86E123F47A DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=bakulin.de; s=default; t=1372978770; bh=sFG/DBaUyN8DRwpJlhE1w6PGSaDHhCEhKPqunQLdDrY=; h=Date:From:To:CC:Subject:References:In-Reply-To; b=S0VFWaesGRSE41sH2hIEukEX5uLSdKC+DRxrwBb/DBtvi0fJ6LB0Atp2irVhj0zVT 7dNoyD0Lzoq0AheLkmQui5eLpmI/c0U1tFQmuMnb69Zxe8qKlwtpXdz1smJv2Cti9e B+LABXFoauJi+cUvR7/iwLRXbKfgoHOqHFhI1Ajg= Message-ID: <51D5FE4C.9060102@bakulin.de> Date: Fri, 05 Jul 2013 00:59:24 +0200 From: Ilya Bakulin MIME-Version: 1.0 To: Warner Losh Subject: Re: [PATCH] SDIO support for Globalscale Dreamplug References: <20130702145905.GA1847@olymp.kibab.com> <51D3097A.8010601@FreeBSD.org> <51D3282C.1090701@bakulin.de> <20130703222002.GA60491@olymp.kibab.com> <51D50C55.1040300@myspectrum.nl> <51D531CB.3060300@bakulin.de> In-Reply-To: <51D531CB.3060300@bakulin.de> X-Enigmail-Version: 1.5.1 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="----enig2WKGGPGDVOVGRXXPJHMSO" Cc: Alexander Motin , freebsd-arm@freebsd.org, freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2013 22:59:39 -0000 This is an OpenPGP/MIME signed message (RFC 4880 and 3156) ------enig2WKGGPGDVOVGRXXPJHMSO Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable I have added some more bus methods and the first prototype of Marvell 802= =2E11 SDIO driver. Right now it is able to attach and read some card-specific information. I'm analyzing the Linux driver and try to do the same things [1]. The next thing that should be done is uploading firmware to the card. My work is kept here: https://github.com/kibab/freebsd/compare/master...k= ibab-dplug#files_bucket I likely won't be able to work further on it during the next week, but please review the code and post your comments. [1] https://github.com/torvalds/linux/blob/master/drivers/net/wireless/mw= ifiex/sdio.c --=20 Regards, Ilya Bakulin ------enig2WKGGPGDVOVGRXXPJHMSO Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.19 (Darwin) Comment: GPGTools - http://gpgtools.org iEYEARECAAYFAlHV/k8ACgkQo9vlj1oadwjjKgCgtM1mYECWO2QsuDxrcPGUGzr3 AxIAn2/fjxC5nfxOho8kMwsjoiThHzfE =NYFS -----END PGP SIGNATURE----- ------enig2WKGGPGDVOVGRXXPJHMSO-- From owner-freebsd-embedded@FreeBSD.ORG Sat Jul 6 12:52:01 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 8B031C42 for ; Sat, 6 Jul 2013 12:52:01 +0000 (UTC) (envelope-from matheus@eternamente.info) Received: from phoenix.eternamente.info (phoenix.eternamente.info [109.169.62.232]) by mx1.freebsd.org (Postfix) with ESMTP id 6710916EF for ; Sat, 6 Jul 2013 12:52:01 +0000 (UTC) Received: by phoenix.eternamente.info (Postfix, from userid 80) id A764A1CC59; Sat, 6 Jul 2013 09:51:47 -0300 (BRT) Received: from 189.124.229.164 (SquirrelMail authenticated user matheus) by arroway.org with HTTP; Sat, 6 Jul 2013 09:51:47 -0300 Message-ID: <177ad5f8896d866e3b46b73e0226af06.squirrel@arroway.org> In-Reply-To: References: <20130701152313.60982@relay.ibs.dn.ua> <20130701220301.1636@relay.ibs.dn.ua> <20130702085213.52064@relay.ibs.dn.ua> <18a9b686d7f49d3773ad63eb853b1c88.squirrel@arroway.org> Date: Sat, 6 Jul 2013 09:51:47 -0300 Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? From: "Nenhum_de_Nos" To: "Luiz Otavio O Souza" User-Agent: SquirrelMail/1.4.21 MIME-Version: 1.0 Content-Type: text/plain;charset=iso-8859-1 Content-Transfer-Encoding: 8bit X-Priority: 3 (Normal) Importance: Normal Cc: freebsd-embedded@freebsd.org X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 06 Jul 2013 12:52:01 -0000 On Tue, July 2, 2013 12:28, Luiz Otavio O Souza wrote: > On 2 July 2013 08:41, Nenhum_de_Nos wrote: > >> Hi all, >> >> I've talked to Luiz some time ago, but I had no time to invest in >> struggling with the serial >> interface. >> >> As I said before, I have a 1043ND and would really like to see it running >> FreeBSD. Imagine this >> hardware running pfSense ? this would be the dlink killer ;) >> >> do I need to upload it to the hardware to tinkle with the build script ? >> First of all I'd like to >> help this way, as my shell skills are better then my coding skills :) >> >> > Hi Matheus, > > If i'm not mistaken you can use the web interface to write a proper > generated image to flash. > > But if anything goes wrong you won't be able to debug without the console > access. > > There are a few scripts to cross build these images (zrouter, adrian's > scripts) which you can start with. > > For pfSense I'm not sure if we have enough RAM on wr1043. > > I've a brand new WR1043 (never plugged in). If you want, contact me in > private and i can provide the help you need to solder the console header on > yours, or we can just exchange our units and i'll send mine with console > headers (and even with FreeBSD installed). > > Luiz Thanks Luiz, but for now, I'd like to try and understand the building code. As said the building scripts could use some help, so I am willing to read them and see if I can help. how can I get them ? svn/cvs ? I will read https://wiki.freebsd.org/FreeBSD/mips/TL-WR1043ND and begin to get to know it. in this thread someone said I can build an image to upload to the unit, from firmware upload page. I want to study this code. When I am in the point of flashing the image to it, I contact again. thanks, matheus -- We will call you Cygnus, The God of balance you shall be A: Because it messes up the order in which people normally read text. Q: Why is top-posting such a bad thing? http://en.wikipedia.org/wiki/Posting_style From owner-freebsd-embedded@FreeBSD.ORG Sat Jul 6 20:19:39 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 94D505DF for ; Sat, 6 Jul 2013 20:19:39 +0000 (UTC) (envelope-from matheus@eternamente.info) Received: from phoenix.eternamente.info (phoenix.eternamente.info [109.169.62.232]) by mx1.freebsd.org (Postfix) with ESMTP id 526D31334 for ; Sat, 6 Jul 2013 20:19:39 +0000 (UTC) Received: by phoenix.eternamente.info (Postfix, from userid 80) id F2A2F1CC59; Sat, 6 Jul 2013 17:19:28 -0300 (BRT) Received: from 189.124.229.164 (SquirrelMail authenticated user matheus) by arroway.org with HTTP; Sat, 6 Jul 2013 17:19:28 -0300 Message-ID: In-Reply-To: References: <20130701152313.60982@relay.ibs.dn.ua> <20130701220301.1636@relay.ibs.dn.ua> <20130702085213.52064@relay.ibs.dn.ua> <18a9b686d7f49d3773ad63eb853b1c88.squirrel@arroway.org> Date: Sat, 6 Jul 2013 17:19:28 -0300 Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? From: "Nenhum_de_Nos" Cc: freebsd-embedded@freebsd.org User-Agent: SquirrelMail/1.4.21 MIME-Version: 1.0 Content-Type: text/plain;charset=iso-8859-1 Content-Transfer-Encoding: 8bit X-Priority: 3 (Normal) Importance: Normal X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 06 Jul 2013 20:19:39 -0000 On Wed, July 3, 2013 10:21, Adrian Chadd wrote: > FreeBSD runs on the TL-WR1043nd. It was my first Atheros SoC port. > > https://wiki.freebsd.org/FreeBSD/mips/TL-WR1043ND adrian, I tried and got: *** Target Done. *** Target : mfsroot *** Deleting old file system.. *** Creating new filesystem... *** Populating filesystem... install: /home/matheus/work/freebsd/head/src/../root/mipseb/sbin/switchctl: No such file or directory *** Target Done. *** Target : fsimage *** Running makefs to build compressed image .. Calculated size of `/home/matheus/work/freebsd/head/src/../mfsroot-tl-wr1043nd.img': 19308544 bytes, 1223 inodes Extent size set to 4096 /home/matheus/work/freebsd/head/src/../mfsroot-tl-wr1043nd.img: 18.4MB (37712 sectors) block size 4096, fragment size 512 using 2 cylinder groups of 12.96MB, 3319 blks, 896 inodes. super-block backups (for fsck -b #) at: 32, 26584, Populating `/home/matheus/work/freebsd/head/src/../mfsroot-tl-wr1043nd.img' Image `/home/matheus/work/freebsd/head/src/../mfsroot-tl-wr1043nd.img' complete *** Running mkuzip to create a compressed filesystem .. *** Target Done. *** Target : tplink 4093+2 records in 4093+1 records out 2096035 bytes transferred in 1.316779 secs (1591789 bytes/sec) [mktplinkfw] *** error: rootfs image is too big and: ls /tftpboot/ kernel.TP-WN1043ND mfsroot-tl-wr1043nd.img.uzip kernel.TP-WN1043ND.symbols I guess this is not expected. how can I troubleshoot this ? and, can I just upload it on the tp-link firmware upload page ? Luiz said that the main issue is that I can't see the boot and solve problems if they appear (if I understand him right). Is this ? thanks, matheus > -adrian > > On 2 July 2013 04:41, Nenhum_de_Nos wrote: >> >> On Tue, July 2, 2013 02:52, Zeus Panchenko wrote: >>> Luiz Otavio O Souza wrote: >>>> >>>> I've successfully used TP-Link MR3220 and MR3420 this way. >>>> >>> >>> thanks for the point >>> >>> what I in general want from the issue is more or less "common" >>> necessities of small (2-10 workplaces) office >>> >>> and it includes: >>> >>> - vi >>> - pf >>> - PPPoE >>> - hostapd >>> - OpenVPN >>> - bsnmpd >>> - network utilities >>> netstat, ifconfig, route, tcpdump >>> - some optional tools >>> -- mtr >>> -- nrpe >>> -- sendmail >>> -- tmux/screen >>> - anything I missed :) >>> >>> so, what are the chances to build image with these? >> >> Hi all, >> >> I've talked to Luiz some time ago, but I had no time to invest in struggling with the serial >> interface. >> >> As I said before, I have a 1043ND and would really like to see it running FreeBSD. Imagine this >> hardware running pfSense ? this would be the dlink killer ;) >> >> do I need to upload it to the hardware to tinkle with the build script ? First of all I'd like >> to >> help this way, as my shell skills are better then my coding skills :) >> >> att, >> >> matheus >> >> -- >> We will call you Cygnus, >> The God of balance you shall be >> >> A: Because it messes up the order in which people normally read text. >> Q: Why is top-posting such a bad thing? >> >> http://en.wikipedia.org/wiki/Posting_style >> _______________________________________________ >> freebsd-embedded@freebsd.org mailing list >> http://lists.freebsd.org/mailman/listinfo/freebsd-embedded >> To unsubscribe, send any mail to "freebsd-embedded-unsubscribe@freebsd.org" > -- We will call you Cygnus, The God of balance you shall be A: Because it messes up the order in which people normally read text. Q: Why is top-posting such a bad thing? http://en.wikipedia.org/wiki/Posting_style From owner-freebsd-embedded@FreeBSD.ORG Sat Jul 6 20:26:00 2013 Return-Path: Delivered-To: freebsd-embedded@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 688A6872 for ; Sat, 6 Jul 2013 20:26:00 +0000 (UTC) (envelope-from matheus@eternamente.info) Received: from phoenix.eternamente.info (phoenix.eternamente.info [109.169.62.232]) by mx1.freebsd.org (Postfix) with ESMTP id 4396B136C for ; Sat, 6 Jul 2013 20:25:59 +0000 (UTC) Received: by phoenix.eternamente.info (Postfix, from userid 80) id BB9AE1CC59; Sat, 6 Jul 2013 17:25:49 -0300 (BRT) Received: from 189.124.229.164 (SquirrelMail authenticated user matheus) by arroway.org with HTTP; Sat, 6 Jul 2013 17:25:49 -0300 Message-ID: <7d75020201891ae6047eea627aadef62.squirrel@arroway.org> In-Reply-To: <177ad5f8896d866e3b46b73e0226af06.squirrel@arroway.org> References: <20130701152313.60982@relay.ibs.dn.ua> <20130701220301.1636@relay.ibs.dn.ua> <20130702085213.52064@relay.ibs.dn.ua> <18a9b686d7f49d3773ad63eb853b1c88.squirrel@arroway.org> <177ad5f8896d866e3b46b73e0226af06.squirrel@arroway.org> Date: Sat, 6 Jul 2013 17:25:49 -0300 Subject: Re: FreeBSD on ASUS, TP-Link and D-Link routers? From: "Nenhum_de_Nos" Cc: freebsd-embedded@freebsd.org User-Agent: SquirrelMail/1.4.21 MIME-Version: 1.0 Content-Type: text/plain;charset=iso-8859-1 Content-Transfer-Encoding: 8bit X-Priority: 3 (Normal) Importance: Normal X-BeenThere: freebsd-embedded@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Dedicated and Embedded Systems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 06 Jul 2013 20:26:00 -0000 On Sat, July 6, 2013 09:51, Nenhum_de_Nos wrote: > > On Tue, July 2, 2013 12:28, Luiz Otavio O Souza wrote: >> On 2 July 2013 08:41, Nenhum_de_Nos wrote: >> >>> Hi all, >>> >>> I've talked to Luiz some time ago, but I had no time to invest in >>> struggling with the serial >>> interface. >>> >>> As I said before, I have a 1043ND and would really like to see it running >>> FreeBSD. Imagine this >>> hardware running pfSense ? this would be the dlink killer ;) >>> >>> do I need to upload it to the hardware to tinkle with the build script ? >>> First of all I'd like to >>> help this way, as my shell skills are better then my coding skills :) >>> >>> >> Hi Matheus, >> >> If i'm not mistaken you can use the web interface to write a proper >> generated image to flash. >> >> But if anything goes wrong you won't be able to debug without the console >> access. >> >> There are a few scripts to cross build these images (zrouter, adrian's >> scripts) which you can start with. >> >> For pfSense I'm not sure if we have enough RAM on wr1043. >> >> I've a brand new WR1043 (never plugged in). If you want, contact me in >> private and i can provide the help you need to solder the console header on >> yours, or we can just exchange our units and i'll send mine with console >> headers (and even with FreeBSD installed). >> >> Luiz > > Thanks Luiz, > > but for now, I'd like to try and understand the building code. As said the building scripts could > use some help, so I am willing to read them and see if I can help. > > how can I get them ? > > svn/cvs ? > > I will read https://wiki.freebsd.org/FreeBSD/mips/TL-WR1043ND and begin to get to know it. > > in this thread someone said I can build an image to upload to the unit, from firmware upload page. > I want to study this code. When I am in the point of flashing the image to it, I contact again. > > thanks, > > matheus Luiz, how can I configure it to use the usb port as storage ? is there a limit to the size of the usb stick ? thanks, matheus -- We will call you Cygnus, The God of balance you shall be A: Because it messes up the order in which people normally read text. Q: Why is top-posting such a bad thing? http://en.wikipedia.org/wiki/Posting_style