diff options
author | Richard Zhu <r65037@freescale.com> | 2013-10-12 03:25:58 -0400 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:05:57 -0400 |
commit | 1abc6093bc1d0ff70af0a2d2a2e6f06a0f93b674 (patch) | |
tree | 50a7a754676c597cc443ec8d740ff899e550245d /drivers/mmc | |
parent | 1296e0073da98f7829e0553d6bc9a3cb860e9f8f (diff) |
ENGR00285671 mmc: setup emmc boot partition configure methods
- Configure boot partition
Expose the interfaces that used to enable the configurations
of the boot mode of the eMMC cards.
usage how-to and examples:
Enable the boot partition 1 boot enabled.
"echo 8 > /sys/devices/soc0/soc.1/2100000.aips-bus/
219c000.usdhc/mmc_host/mmc2/mmc2\:0001/boot_config"
In order to make sure that the re-read the ext-csd of card
can be completed successfully, add the method to wait for
the finish of the busy state.
- setup boot_info message output
Output bit means of important esd_csd register
Read esd_csd info each time when cat boot_info
becasue user may change config affect esd_csd
value.
- Boot partition access howto:
About the details, please refer to the guidance of
Documentation/mmc/mmc-dev-parts.txt
To enable write access to /dev/mmcblkXbootY, disable the forced
read-only access with:
echo 0 > /sys/block/mmcblkXbootY/force_ro
To re-enable read-only access:
echo 1 > /sys/block/mmcblkXbootY/force_ro
NOTE:
- The definitions of the EXT_CSD_PART_CONFIG and EXT_CSD_BOOT_BUS_WIDTH
+------------------------------------------------------------+
| Bit7 | Bit6 | Bit5 Bit4 Bit3 | Bit2 Bit1 Bit0 |
|------|----------|-----------------------|------------------|
| X | BOOT_ACK | BOOT_PARTITION_ENABLE | PARTITION_ACCESS |
+------------------------------------------------------------+
Bit7: Reserved
Bit6: always set to vaule '1' when boot_part is enabled
Bit[5:3]:
0x0 : Device not boot enabled (default)
0x1 : Boot partition 1 enabled for boot
0x2 : Boot partition 2 enabled for boot
0x7 : User area enabled for boot
Bit[2:0]:
0x0 : No access to boot partition (default)
0x1 : R/W boot partition 1
0x2 : R/W boot partition 2
+--------------------------------------------------------------------+
| Bit7 Bit6 Bit5 | Bit4 Bit3 | Bit2 | Bit1 Bit0 |
|----------------|----------------------------------|----------------|
| X | BOOT_MODE | RESET_BOOT_BUS_WIDTH | BOOT_BUS_WIDTH |
+--------------------------------------------------------------------+
Bit [4:3] : BOOT_MODE (non-volatile)
0x0 : Use single data rate + backward compatible timings in boot
operation (default)
0x1 : Use single data rate + high speed timings in boot operation mode
0x2 : Use dual data rate in boot operation
0x3 : Reserved
Bit [2]: RESET_BOOT_BUS_WIDTH (non-volatile)
0x0 : Reset bus width to x1, single data rate and backward compatible
timings after boot operation (default)
0x1 : Retain boot bus width and boot mode after boot operation
Bit[1:0] : BOOT_BUS_WIDTH (non-volatile)
0x0 : x1 (sdr) or x4 (ddr) bus width in boot operation mode (default)
0x1 : x4 (sdr/ddr) bus width in boot operation mode
0x2 : x8 (sdr/ddr) bus width in boot operation mode
0x3 : Reserved
- example of the boot_info:
boot_info:0x07;
ALT_BOOT_MODE:1 - Supports alternate boot method
DDR_BOOT_MODE:1 - Supports alternate dual data rate during boot
HS_BOOTMODE:1 - Supports high speed timing during boot
boot_size:2048KB
boot_partition:0x48;
BOOT_ACK:1 - Boot acknowledge sent during boot operation
BOOT_PARTITION-ENABLE: 1 - Boot partition 1 enabled
PARTITION_ACCESS:0 - No access to boot partition
boot_bus:0x00
BOOT_MODE:0 - Use single data rate + backward compatible timings
in boot operation
RESET_BOOT_BUS_WIDTH:0 - Reset bus width to x1, single data rate
and backwardcompatible timings after boot operation
BOOT_BUS_WIDTH:0 - x1 (sdr) or x4 (ddr) bus width in boot
operation mode
Signed-off-by: Richard Zhu <r65037@freescale.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/core/mmc.c | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 0cbd1effe960..13814148077e 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c | |||
@@ -316,6 +316,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
316 | mmc_card_set_blockaddr(card); | 316 | mmc_card_set_blockaddr(card); |
317 | } | 317 | } |
318 | 318 | ||
319 | card->ext_csd.boot_info = ext_csd[EXT_CSD_BOOT_INFO]; | ||
320 | card->ext_csd.boot_config = ext_csd[EXT_CSD_PART_CONFIG]; | ||
321 | card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT]; | ||
322 | card->ext_csd.boot_bus_width = ext_csd[EXT_CSD_BOOT_BUS_WIDTH]; | ||
323 | |||
319 | card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; | 324 | card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; |
320 | mmc_select_card_type(card); | 325 | mmc_select_card_type(card); |
321 | 326 | ||
@@ -616,6 +621,372 @@ out: | |||
616 | return err; | 621 | return err; |
617 | } | 622 | } |
618 | 623 | ||
624 | static ssize_t mmc_boot_info_show(struct device *dev, | ||
625 | struct device_attribute *attr, char *buf) | ||
626 | { | ||
627 | char *boot_partition[8] = { | ||
628 | "Device not boot enabled", | ||
629 | "Boot partition 1 enabled", | ||
630 | "Boot partition 2 enabled", | ||
631 | "Reserved", | ||
632 | "Reserved", | ||
633 | "Reserved", | ||
634 | "Reserved", | ||
635 | "User area enabled for boot"}; | ||
636 | |||
637 | char *bus_width[4] = { | ||
638 | "x1 (sdr) or x4 (ddr) bus width in boot operation mode", | ||
639 | "x4 (sdr/ddr) bus width in boot operation mode", | ||
640 | "x8 (sdr/ddr) bus width in boot operation mode", | ||
641 | "Reserved"}; | ||
642 | |||
643 | char *boot_mode[4] = { | ||
644 | "Use single data rate + backward compatible timings in boot operation", | ||
645 | "Use single data rate + high speed timings in boot operation mode", | ||
646 | "Use dual data rate in boot operation", | ||
647 | "Reserved"}; | ||
648 | |||
649 | int partition; | ||
650 | int width; | ||
651 | int mode; | ||
652 | int err; | ||
653 | u8 *ext_csd = NULL; | ||
654 | struct mmc_card *card = container_of(dev, struct mmc_card, dev); | ||
655 | |||
656 | /* read it again because user may change it */ | ||
657 | mmc_claim_host(card->host); | ||
658 | err = mmc_get_ext_csd(card, &ext_csd); | ||
659 | mmc_release_host(card->host); | ||
660 | if (err || !ext_csd) { | ||
661 | pr_err("%s: failed to get ext_csd, err=%d\n", | ||
662 | mmc_hostname(card->host), | ||
663 | err); | ||
664 | return err; | ||
665 | } | ||
666 | |||
667 | mmc_read_ext_csd(card, ext_csd); | ||
668 | mmc_free_ext_csd(ext_csd); | ||
669 | |||
670 | partition = (card->ext_csd.boot_config >> 3) & 0x7; | ||
671 | width = card->ext_csd.boot_bus_width & 0x3; | ||
672 | mode = (card->ext_csd.boot_bus_width >> 3) & 0x3; | ||
673 | |||
674 | return sprintf(buf, | ||
675 | "boot_info:0x%02x;\n" | ||
676 | " ALT_BOOT_MODE:%x - %s\n" | ||
677 | " DDR_BOOT_MODE:%x - %s\n" | ||
678 | " HS_BOOTMODE:%x - %s\n" | ||
679 | "boot_size:%04dKB\n" | ||
680 | "boot_partition:0x%02x;\n" | ||
681 | " BOOT_ACK:%x - %s\n" | ||
682 | " BOOT_PARTITION-ENABLE: %x - %s\n" | ||
683 | "boot_bus:0x%02x\n" | ||
684 | " BOOT_MODE:%x - %s\n" | ||
685 | " RESET_BOOT_BUS_WIDTH:%x - %s\n" | ||
686 | " BOOT_BUS_WIDTH:%x - %s\n", | ||
687 | |||
688 | card->ext_csd.boot_info, | ||
689 | !!(card->ext_csd.boot_info & 0x1), | ||
690 | (card->ext_csd.boot_info & 0x1) ? | ||
691 | "Supports alternate boot method" : | ||
692 | "Does not support alternate boot method", | ||
693 | !!(card->ext_csd.boot_info & 0x2), | ||
694 | (card->ext_csd.boot_info & 0x2) ? | ||
695 | "Supports alternate dual data rate during boot" : | ||
696 | "Does not support dual data rate during boot", | ||
697 | !!(card->ext_csd.boot_info & 0x4), | ||
698 | (card->ext_csd.boot_info & 0x4) ? | ||
699 | "Supports high speed timing during boot" : | ||
700 | "Does not support high speed timing during boot", | ||
701 | |||
702 | card->ext_csd.boot_size * 128, | ||
703 | |||
704 | card->ext_csd.boot_config, | ||
705 | !!(card->ext_csd.boot_config & 0x40), | ||
706 | (card->ext_csd.boot_config & 0x40) ? | ||
707 | "Boot acknowledge sent during boot operation" : | ||
708 | "No boot acknowledge sent", | ||
709 | partition, | ||
710 | boot_partition[partition], | ||
711 | |||
712 | card->ext_csd.boot_bus_width, | ||
713 | mode, | ||
714 | boot_mode[mode], | ||
715 | !!(card->ext_csd.boot_bus_width & 0x4), | ||
716 | (card->ext_csd.boot_bus_width & 0x4) ? | ||
717 | "Retain boot bus width and boot mode after boot operation" : | ||
718 | "Reset bus width to x1, single data rate and backward" | ||
719 | "compatible timings after boot operation", | ||
720 | width, | ||
721 | bus_width[width]); | ||
722 | } | ||
723 | |||
724 | /* set up boot partitions */ | ||
725 | static ssize_t | ||
726 | setup_boot_partitions(struct device *dev, struct device_attribute *attr, | ||
727 | const char *buf, size_t count) | ||
728 | { | ||
729 | int err, busy = 0; | ||
730 | u32 part; | ||
731 | u8 *ext_csd, boot_config; | ||
732 | struct mmc_command cmd; | ||
733 | struct mmc_card *card = container_of(dev, struct mmc_card, dev); | ||
734 | |||
735 | BUG_ON(!card); | ||
736 | |||
737 | sscanf(buf, "%d\n", &part); | ||
738 | |||
739 | if (card->csd.mmca_vsn < CSD_SPEC_VER_4) { | ||
740 | pr_err("%s: invalid mmc version" \ | ||
741 | " mmc version is below version 4!)\n", | ||
742 | mmc_hostname(card->host)); | ||
743 | return -EINVAL; | ||
744 | } | ||
745 | |||
746 | /* it's a normal SD/MMC but user request to configure boot partition */ | ||
747 | if (card->ext_csd.boot_size <= 0) { | ||
748 | pr_err("%s: fail to send SWITCH command to card " \ | ||
749 | "to update boot_config of the EXT_CSD!\n", | ||
750 | mmc_hostname(card->host)); | ||
751 | return -EINVAL; | ||
752 | } | ||
753 | |||
754 | /* | ||
755 | * partition must be - | ||
756 | * 0 - user area | ||
757 | * 1 - boot partition 1 | ||
758 | * 2 - boot partition 2 | ||
759 | * DO NOT switch the partitions that used to be accessed | ||
760 | * in OS layer HERE | ||
761 | */ | ||
762 | if (part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) { | ||
763 | pr_err("%s: DO NOT switch the partitions that used to be\n" \ | ||
764 | " accessed in OS layer HERE. please following the\n" \ | ||
765 | " guidance of Documentation/mmc/mmc-dev-parts.txt.\n", | ||
766 | mmc_hostname(card->host)); | ||
767 | return -EINVAL; | ||
768 | } | ||
769 | |||
770 | ext_csd = kmalloc(512, GFP_KERNEL); | ||
771 | if (!ext_csd) { | ||
772 | pr_err("%s: could not allocate a buffer to " \ | ||
773 | "receive the ext_csd.\n", mmc_hostname(card->host)); | ||
774 | return -ENOMEM; | ||
775 | } | ||
776 | |||
777 | mmc_claim_host(card->host); | ||
778 | err = mmc_send_ext_csd(card, ext_csd); | ||
779 | if (err) { | ||
780 | pr_err("%s: unable to read EXT_CSD.\n", | ||
781 | mmc_hostname(card->host)); | ||
782 | goto err_rtn; | ||
783 | } | ||
784 | |||
785 | /* enable the boot partition in boot mode */ | ||
786 | /* boot enable be - | ||
787 | * 0x00 - disable boot enable. | ||
788 | * 0x08 - boot partition 1 is enabled for boot. | ||
789 | * 0x10 - boot partition 2 is enabled for boot. | ||
790 | * 0x38 - User area is enabled for boot. | ||
791 | */ | ||
792 | switch (part & EXT_CSD_BOOT_PARTITION_ENABLE_MASK) { | ||
793 | case 0: | ||
794 | boot_config = (ext_csd[EXT_CSD_PART_CONFIG] | ||
795 | & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK | ||
796 | & ~EXT_CSD_BOOT_ACK_ENABLE); | ||
797 | break; | ||
798 | case EXT_CSD_BOOT_PARTITION_PART1: | ||
799 | boot_config = ((ext_csd[EXT_CSD_PART_CONFIG] | ||
800 | & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK) | ||
801 | | EXT_CSD_BOOT_PARTITION_PART1 | ||
802 | | EXT_CSD_BOOT_ACK_ENABLE); | ||
803 | break; | ||
804 | case EXT_CSD_BOOT_PARTITION_PART2: | ||
805 | boot_config = ((ext_csd[EXT_CSD_PART_CONFIG] | ||
806 | & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK) | ||
807 | | EXT_CSD_BOOT_PARTITION_PART2 | ||
808 | | EXT_CSD_BOOT_ACK_ENABLE); | ||
809 | break; | ||
810 | case EXT_CSD_BOOT_PARTITION_ENABLE_MASK: | ||
811 | boot_config = ((ext_csd[EXT_CSD_PART_CONFIG] | ||
812 | | EXT_CSD_BOOT_PARTITION_ENABLE_MASK) | ||
813 | & ~EXT_CSD_BOOT_ACK_ENABLE); | ||
814 | break; | ||
815 | default: | ||
816 | pr_err("%s: wrong boot config parameter" \ | ||
817 | " 00 (disable boot), 08 (enable boot1)," \ | ||
818 | "16 (enable boot2), 56 (User area)\n", | ||
819 | mmc_hostname(card->host)); | ||
820 | err = -EINVAL; | ||
821 | goto err_rtn; | ||
822 | } | ||
823 | |||
824 | err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||
825 | EXT_CSD_PART_CONFIG, boot_config, card->ext_csd.part_time); | ||
826 | if (err) { | ||
827 | pr_err("%s: fail to send SWITCH command to card " \ | ||
828 | "to update boot_config of the EXT_CSD!\n", | ||
829 | mmc_hostname(card->host)); | ||
830 | goto err_rtn; | ||
831 | } | ||
832 | |||
833 | /* waiting for the card to finish the busy state */ | ||
834 | do { | ||
835 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
836 | |||
837 | cmd.opcode = MMC_SEND_STATUS; | ||
838 | cmd.arg = card->rca << 16; | ||
839 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
840 | |||
841 | err = mmc_wait_for_cmd(card->host, &cmd, 0); | ||
842 | if (err || busy > 100) { | ||
843 | pr_err("%s: failed to wait for" \ | ||
844 | "the busy state to end.\n", | ||
845 | mmc_hostname(card->host)); | ||
846 | break; | ||
847 | } | ||
848 | |||
849 | if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) { | ||
850 | pr_info("%s: card is in busy state" \ | ||
851 | "pls wait for busy state to end.\n", | ||
852 | mmc_hostname(card->host)); | ||
853 | } | ||
854 | busy++; | ||
855 | } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); | ||
856 | |||
857 | /* Now check whether it works */ | ||
858 | err = mmc_send_ext_csd(card, ext_csd); | ||
859 | if (err) { | ||
860 | pr_err("%s: %d unable to re-read EXT_CSD.\n", | ||
861 | mmc_hostname(card->host), err); | ||
862 | goto err_rtn; | ||
863 | } | ||
864 | |||
865 | card->ext_csd.boot_config = ext_csd[EXT_CSD_PART_CONFIG]; | ||
866 | |||
867 | err_rtn: | ||
868 | mmc_release_host(card->host); | ||
869 | kfree(ext_csd); | ||
870 | if (err) | ||
871 | return err; | ||
872 | else | ||
873 | return count; | ||
874 | } | ||
875 | |||
876 | /* configure the boot bus */ | ||
877 | static ssize_t | ||
878 | setup_boot_bus(struct device *dev, struct device_attribute *attr, | ||
879 | const char *buf, size_t count) | ||
880 | { | ||
881 | int err, busy = 0; | ||
882 | u32 boot_bus, new_bus; | ||
883 | u8 *ext_csd; | ||
884 | struct mmc_command cmd; | ||
885 | struct mmc_card *card = container_of(dev, struct mmc_card, dev); | ||
886 | |||
887 | BUG_ON(!card); | ||
888 | |||
889 | sscanf(buf, "%d\n", &boot_bus); | ||
890 | |||
891 | if (card->csd.mmca_vsn < CSD_SPEC_VER_4) { | ||
892 | pr_err("%s: invalid mmc version" \ | ||
893 | " mmc version is below version 4!)\n", | ||
894 | mmc_hostname(card->host)); | ||
895 | return -EINVAL; | ||
896 | } | ||
897 | |||
898 | /* it's a normal SD/MMC but user request to configure boot bus */ | ||
899 | if (card->ext_csd.boot_size <= 0) { | ||
900 | pr_err("%s: this is a normal SD/MMC card" \ | ||
901 | " but you request to configure boot bus !\n", | ||
902 | mmc_hostname(card->host)); | ||
903 | return -EINVAL; | ||
904 | } | ||
905 | |||
906 | ext_csd = kmalloc(512, GFP_KERNEL); | ||
907 | if (!ext_csd) { | ||
908 | pr_err("%s: could not allocate a buffer to " \ | ||
909 | "receive the ext_csd.\n", mmc_hostname(card->host)); | ||
910 | return -ENOMEM; | ||
911 | } | ||
912 | |||
913 | mmc_claim_host(card->host); | ||
914 | err = mmc_send_ext_csd(card, ext_csd); | ||
915 | if (err) { | ||
916 | pr_err("%s: unable to read EXT_CSD.\n", | ||
917 | mmc_hostname(card->host)); | ||
918 | goto err_rtn; | ||
919 | } | ||
920 | |||
921 | /* Configure the boot bus width when boot partition is enabled */ | ||
922 | if (((boot_bus & EXT_CSD_BOOT_BUS_WIDTH_MODE_MASK) >> 3) > 2 | ||
923 | || (boot_bus & EXT_CSD_BOOT_BUS_WIDTH_WIDTH_MASK) > 2 | ||
924 | || (boot_bus & ~EXT_CSD_BOOT_BUS_WIDTH_MASK) > 0) { | ||
925 | pr_err("%s: Invalid inputs!\n", | ||
926 | mmc_hostname(card->host)); | ||
927 | err = -EINVAL; | ||
928 | goto err_rtn; | ||
929 | } | ||
930 | |||
931 | err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||
932 | EXT_CSD_BOOT_BUS_WIDTH, boot_bus, card->ext_csd.part_time); | ||
933 | if (err) { | ||
934 | pr_err("%s: fail to send SWITCH command to card " \ | ||
935 | "to update boot_config of the EXT_CSD!\n", | ||
936 | mmc_hostname(card->host)); | ||
937 | goto err_rtn; | ||
938 | } | ||
939 | |||
940 | /* waiting for the card to finish the busy state */ | ||
941 | do { | ||
942 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
943 | |||
944 | cmd.opcode = MMC_SEND_STATUS; | ||
945 | cmd.arg = card->rca << 16; | ||
946 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
947 | |||
948 | err = mmc_wait_for_cmd(card->host, &cmd, 0); | ||
949 | if (err || busy > 100) { | ||
950 | pr_err("%s: failed to wait for" \ | ||
951 | "the busy state to end.\n", | ||
952 | mmc_hostname(card->host)); | ||
953 | break; | ||
954 | } | ||
955 | |||
956 | if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) { | ||
957 | pr_info("%s: card is in busy state" \ | ||
958 | "pls wait for busy state to end.\n", | ||
959 | mmc_hostname(card->host)); | ||
960 | } | ||
961 | busy++; | ||
962 | } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); | ||
963 | |||
964 | /* Now check whether it works */ | ||
965 | err = mmc_send_ext_csd(card, ext_csd); | ||
966 | if (err) { | ||
967 | pr_err("%s: %d unable to re-read EXT_CSD.\n", | ||
968 | mmc_hostname(card->host), err); | ||
969 | goto err_rtn; | ||
970 | } | ||
971 | |||
972 | new_bus = ext_csd[EXT_CSD_BOOT_BUS_WIDTH]; | ||
973 | if (boot_bus != new_bus) { | ||
974 | pr_err("%s: after SWITCH, current boot bus mode %d" \ | ||
975 | " is not same as requested bus mode %d!\n", | ||
976 | mmc_hostname(card->host), new_bus, boot_bus); | ||
977 | goto err_rtn; | ||
978 | } | ||
979 | card->ext_csd.boot_bus_width = ext_csd[EXT_CSD_BOOT_BUS_WIDTH]; | ||
980 | |||
981 | err_rtn: | ||
982 | mmc_release_host(card->host); | ||
983 | mmc_free_ext_csd(ext_csd); | ||
984 | if (err) | ||
985 | return err; | ||
986 | else | ||
987 | return count; | ||
988 | } | ||
989 | |||
619 | MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], | 990 | MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], |
620 | card->raw_cid[2], card->raw_cid[3]); | 991 | card->raw_cid[2], card->raw_cid[3]); |
621 | MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], | 992 | MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], |
@@ -635,6 +1006,9 @@ MMC_DEV_ATTR(enhanced_area_offset, "%llu\n", | |||
635 | MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); | 1006 | MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); |
636 | MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); | 1007 | MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); |
637 | MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); | 1008 | MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); |
1009 | DEVICE_ATTR(boot_info, S_IRUGO, mmc_boot_info_show, NULL); | ||
1010 | DEVICE_ATTR(boot_config, S_IWUGO, NULL, setup_boot_partitions); | ||
1011 | DEVICE_ATTR(boot_bus_config, S_IWUGO, NULL, setup_boot_bus); | ||
638 | 1012 | ||
639 | static struct attribute *mmc_std_attrs[] = { | 1013 | static struct attribute *mmc_std_attrs[] = { |
640 | &dev_attr_cid.attr, | 1014 | &dev_attr_cid.attr, |
@@ -653,6 +1027,9 @@ static struct attribute *mmc_std_attrs[] = { | |||
653 | &dev_attr_enhanced_area_size.attr, | 1027 | &dev_attr_enhanced_area_size.attr, |
654 | &dev_attr_raw_rpmb_size_mult.attr, | 1028 | &dev_attr_raw_rpmb_size_mult.attr, |
655 | &dev_attr_rel_sectors.attr, | 1029 | &dev_attr_rel_sectors.attr, |
1030 | &dev_attr_boot_info.attr, | ||
1031 | &dev_attr_boot_config.attr, | ||
1032 | &dev_attr_boot_bus_config.attr, | ||
656 | NULL, | 1033 | NULL, |
657 | }; | 1034 | }; |
658 | 1035 | ||